From 67ea817550589912d0ce67e0062aaa9654d4082f Mon Sep 17 00:00:00 2001 From: gribok <40306040+gribok@users.noreply.github.com> Date: Tue, 17 Mar 2020 23:17:23 +0000 Subject: [PATCH 1/4] add testsuite for unit- and integratin testing for ExpDev07/coronavirus-tracker-api#64 --- Pipfile | 2 + Pipfile.lock | 170 +++++++++++++++++- README.md | 11 +- tests/__init__.py | 0 .../time_series_19-covid-Confirmed.csv | 11 ++ .../time_series_19-covid-Deaths.csv | 11 ++ .../time_series_19-covid-Recovered.csv | 11 ++ tests/expected_output/data_confirmed.json | 1 + tests/expected_output/data_deaths.json | 1 + tests/expected_output/data_recovered.json | 1 + tests/test_countrycodes.py | 23 +++ tests/test_data.py | 71 ++++++++ tests/test_date.py | 19 ++ tests/test_routes.py | 66 +++++++ 14 files changed, 385 insertions(+), 13 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/example_data/time_series_19-covid-Confirmed.csv create mode 100644 tests/example_data/time_series_19-covid-Deaths.csv create mode 100644 tests/example_data/time_series_19-covid-Recovered.csv create mode 100644 tests/expected_output/data_confirmed.json create mode 100644 tests/expected_output/data_deaths.json create mode 100644 tests/expected_output/data_recovered.json create mode 100644 tests/test_countrycodes.py create mode 100644 tests/test_data.py create mode 100644 tests/test_date.py create mode 100644 tests/test_routes.py diff --git a/Pipfile b/Pipfile index a62c1060..104c27c8 100644 --- a/Pipfile +++ b/Pipfile @@ -5,6 +5,8 @@ verify_ssl = true [dev-packages] bandit = "*" +pytest = "*" +pylint = "*" [packages] flask = "*" diff --git a/Pipfile.lock b/Pipfile.lock index a33e8fab..bcc795ad 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9b90b4505a8c954d95802f5f614e3c7ba47e709949ef2e0817bb2625476d49cd" + "sha256": "3ca964b855d418f59464ea8c7de126e18ab3f8ff5c7142d774468f95d9a1156c" }, "pipfile-spec": 6, "requires": { @@ -175,6 +175,20 @@ } }, "develop": { + "astroid": { + "hashes": [ + "sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a", + "sha256:840947ebfa8b58f318d42301cf8c0a20fd794a33b61cc4638e28e9e61ba32f42" + ], + "version": "==2.3.3" + }, + "attrs": { + "hashes": [ + "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", + "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" + ], + "version": "==19.3.0" + }, "bandit": { "hashes": [ "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952", @@ -183,14 +197,6 @@ "index": "pypi", "version": "==1.6.2" }, - "colorama": { - "hashes": [ - "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff", - "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1" - ], - "markers": "platform_system == 'Windows'", - "version": "==0.4.3" - }, "gitdb": { "hashes": [ "sha256:284a6a4554f954d6e737cddcff946404393e030b76a282c6640df8efd6b3da5e", @@ -205,6 +211,68 @@ ], "version": "==3.1.0" }, + "importlib-metadata": { + "hashes": [ + "sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302", + "sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b" + ], + "markers": "python_version < '3.8'", + "version": "==1.5.0" + }, + "isort": { + "hashes": [ + "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", + "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + ], + "version": "==4.3.21" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d", + "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449", + "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08", + "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a", + "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50", + "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd", + "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239", + "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb", + "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea", + "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e", + "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156", + "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142", + "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442", + "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62", + "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db", + "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531", + "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383", + "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a", + "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357", + "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4", + "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0" + ], + "version": "==1.4.3" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "more-itertools": { + "hashes": [ + "sha256:5dd8bcf33e5f9513ffa06d5ad33d78f31e1931ac9a18f33d37e77a180d393a7c", + "sha256:b1ddb932186d8a6ac451e1d95844b382f55e12686d51ca0c68b6f61f2ab7a507" + ], + "version": "==8.2.0" + }, + "packaging": { + "hashes": [ + "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3", + "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752" + ], + "version": "==20.3" + }, "pbr": { "hashes": [ "sha256:139d2625547dbfa5fb0b81daebb39601c478c21956dc57e2e07b74450a8c506b", @@ -212,6 +280,43 @@ ], "version": "==5.4.4" }, + "pluggy": { + "hashes": [ + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + ], + "version": "==0.13.1" + }, + "py": { + "hashes": [ + "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa", + "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0" + ], + "version": "==1.8.1" + }, + "pylint": { + "hashes": [ + "sha256:3db5468ad013380e987410a8d6956226963aed94ecb5f9d3a28acca6d9ac36cd", + "sha256:886e6afc935ea2590b462664b161ca9a5e40168ea99e5300935f6591ad467df4" + ], + "index": "pypi", + "version": "==2.4.4" + }, + "pyparsing": { + "hashes": [ + "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f", + "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec" + ], + "version": "==2.4.6" + }, + "pytest": { + "hashes": [ + "sha256:0e5b30f5cb04e887b91b1ee519fa3d89049595f428c1db76e73bd7f17b09b172", + "sha256:84dde37075b8805f3d1f392cc47e38a0e59518fb46a431cfdaf7cf1ce805f970" + ], + "index": "pypi", + "version": "==5.4.1" + }, "pyyaml": { "hashes": [ "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6", @@ -248,6 +353,53 @@ "sha256:a4e7dc759fb0f2e3e2f7d8ffe2358c19d45b9b8297f393ef1256858d82f69c9b" ], "version": "==1.32.0" + }, + "typed-ast": { + "hashes": [ + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" + ], + "markers": "implementation_name == 'cpython' and python_version < '3.8'", + "version": "==1.4.1" + }, + "wcwidth": { + "hashes": [ + "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603", + "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8" + ], + "version": "==0.1.8" + }, + "wrapt": { + "hashes": [ + "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" + ], + "version": "==1.11.2" + }, + "zipp": { + "hashes": [ + "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b", + "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96" + ], + "version": "==3.1.0" } } } diff --git a/README.md b/README.md index 02caa8d7..3c024305 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ GET /confirmed ```json { "latest": 42767, - "locations": [ ... ], - "last_updated": "2020-03-07T18:08:58.432242Z", - "source": "https://github.com/ExpDev07/coronavirus-tracker-api" + "locations": [ ... ], + "last_updated": "2020-03-07T18:08:58.432242Z", + "source": "https://github.com/ExpDev07/coronavirus-tracker-api" } ``` @@ -85,8 +85,12 @@ You will need the following things properly installed on your computer. ### Running Tests +* `py.test -s -v tests/` + ### Linting +* `pylint app/` + ### Building ### Deploying @@ -113,4 +117,3 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d ## License The data is available to the public strictly for educational and academic research purposes. Please link to this repo somewhere in your project if you can (not required) :). - diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/example_data/time_series_19-covid-Confirmed.csv b/tests/example_data/time_series_19-covid-Confirmed.csv new file mode 100644 index 00000000..e59e1499 --- /dev/null +++ b/tests/example_data/time_series_19-covid-Confirmed.csv @@ -0,0 +1,11 @@ +Province/State,Country/Region,Lat,Long,1/22/20,1/23/20,1/24/20,1/25/20,1/26/20,1/27/20,1/28/20,1/29/20,1/30/20,1/31/20,2/1/20,2/2/20,2/3/20,2/4/20,2/5/20,2/6/20,2/7/20,2/8/20,2/9/20,2/10/20,2/11/20,2/12/20,2/13/20,2/14/20,2/15/20,2/16/20,2/17/20,2/18/20,2/19/20,2/20/20,2/21/20,2/22/20,2/23/20,2/24/20,2/25/20,2/26/20,2/27/20,2/28/20,2/29/20,3/1/20,3/2/20,3/3/20,3/4/20,3/5/20,3/6/20,3/7/20,3/8/20,3/9/20,3/10/20,3/11/20,3/12/20,3/13/20,3/14/20,3/15/20 +,Thailand,15,101,2,3,5,7,8,8,14,14,14,19,19,19,19,25,25,25,25,32,32,32,33,33,33,33,33,34,35,35,35,35,35,35,35,35,37,40,40,41,42,42,43,43,43,47,48,50,50,50,53,59,70,75,82,114 +,Japan,36,138,2,1,2,2,4,4,7,7,11,15,20,20,20,22,22,45,25,25,26,26,26,28,28,29,43,59,66,74,84,94,105,122,147,159,170,189,214,228,241,256,274,293,331,360,420,461,502,511,581,639,639,701,773,839 +,Singapore,1.2833,103.8333,0,1,3,3,4,5,7,7,10,13,16,18,18,24,28,28,30,33,40,45,47,50,58,67,72,75,77,81,84,84,85,85,89,89,91,93,93,93,102,106,108,110,110,117,130,138,150,150,160,178,178,200,212,226 +,Nepal,28.1667,84.25,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +,Malaysia,2.5,112.5,0,0,0,3,4,4,4,7,8,8,8,8,8,10,12,12,12,16,16,18,18,18,19,19,22,22,22,22,22,22,22,22,22,22,22,22,23,23,25,29,29,36,50,50,83,93,99,117,129,149,149,197,238,428 +British Columbia,Canada,49.2827,-123.1207,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,4,4,4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,9,12,13,21,21,27,32,32,39,46,64,64,73 +New South Wales,Australia,-33.8688,151.2093,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,6,6,13,22,22,26,28,38,48,55,65,65,92,112,134 +Victoria,Australia,-37.8136,144.9631,0,0,0,0,1,1,1,1,2,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,7,7,9,9,10,10,10,11,11,15,18,21,21,36,49,57 +Queensland,Australia,-28.0167,153.4,0,0,0,0,0,0,0,1,3,2,3,2,2,3,3,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,9,9,9,11,11,13,13,13,15,15,18,20,20,35,46,61 +,Cambodia,11.55,104.9167,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,5,7,7 diff --git a/tests/example_data/time_series_19-covid-Deaths.csv b/tests/example_data/time_series_19-covid-Deaths.csv new file mode 100644 index 00000000..e59e1499 --- /dev/null +++ b/tests/example_data/time_series_19-covid-Deaths.csv @@ -0,0 +1,11 @@ +Province/State,Country/Region,Lat,Long,1/22/20,1/23/20,1/24/20,1/25/20,1/26/20,1/27/20,1/28/20,1/29/20,1/30/20,1/31/20,2/1/20,2/2/20,2/3/20,2/4/20,2/5/20,2/6/20,2/7/20,2/8/20,2/9/20,2/10/20,2/11/20,2/12/20,2/13/20,2/14/20,2/15/20,2/16/20,2/17/20,2/18/20,2/19/20,2/20/20,2/21/20,2/22/20,2/23/20,2/24/20,2/25/20,2/26/20,2/27/20,2/28/20,2/29/20,3/1/20,3/2/20,3/3/20,3/4/20,3/5/20,3/6/20,3/7/20,3/8/20,3/9/20,3/10/20,3/11/20,3/12/20,3/13/20,3/14/20,3/15/20 +,Thailand,15,101,2,3,5,7,8,8,14,14,14,19,19,19,19,25,25,25,25,32,32,32,33,33,33,33,33,34,35,35,35,35,35,35,35,35,37,40,40,41,42,42,43,43,43,47,48,50,50,50,53,59,70,75,82,114 +,Japan,36,138,2,1,2,2,4,4,7,7,11,15,20,20,20,22,22,45,25,25,26,26,26,28,28,29,43,59,66,74,84,94,105,122,147,159,170,189,214,228,241,256,274,293,331,360,420,461,502,511,581,639,639,701,773,839 +,Singapore,1.2833,103.8333,0,1,3,3,4,5,7,7,10,13,16,18,18,24,28,28,30,33,40,45,47,50,58,67,72,75,77,81,84,84,85,85,89,89,91,93,93,93,102,106,108,110,110,117,130,138,150,150,160,178,178,200,212,226 +,Nepal,28.1667,84.25,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +,Malaysia,2.5,112.5,0,0,0,3,4,4,4,7,8,8,8,8,8,10,12,12,12,16,16,18,18,18,19,19,22,22,22,22,22,22,22,22,22,22,22,22,23,23,25,29,29,36,50,50,83,93,99,117,129,149,149,197,238,428 +British Columbia,Canada,49.2827,-123.1207,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,4,4,4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,9,12,13,21,21,27,32,32,39,46,64,64,73 +New South Wales,Australia,-33.8688,151.2093,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,6,6,13,22,22,26,28,38,48,55,65,65,92,112,134 +Victoria,Australia,-37.8136,144.9631,0,0,0,0,1,1,1,1,2,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,7,7,9,9,10,10,10,11,11,15,18,21,21,36,49,57 +Queensland,Australia,-28.0167,153.4,0,0,0,0,0,0,0,1,3,2,3,2,2,3,3,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,9,9,9,11,11,13,13,13,15,15,18,20,20,35,46,61 +,Cambodia,11.55,104.9167,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,5,7,7 diff --git a/tests/example_data/time_series_19-covid-Recovered.csv b/tests/example_data/time_series_19-covid-Recovered.csv new file mode 100644 index 00000000..e59e1499 --- /dev/null +++ b/tests/example_data/time_series_19-covid-Recovered.csv @@ -0,0 +1,11 @@ +Province/State,Country/Region,Lat,Long,1/22/20,1/23/20,1/24/20,1/25/20,1/26/20,1/27/20,1/28/20,1/29/20,1/30/20,1/31/20,2/1/20,2/2/20,2/3/20,2/4/20,2/5/20,2/6/20,2/7/20,2/8/20,2/9/20,2/10/20,2/11/20,2/12/20,2/13/20,2/14/20,2/15/20,2/16/20,2/17/20,2/18/20,2/19/20,2/20/20,2/21/20,2/22/20,2/23/20,2/24/20,2/25/20,2/26/20,2/27/20,2/28/20,2/29/20,3/1/20,3/2/20,3/3/20,3/4/20,3/5/20,3/6/20,3/7/20,3/8/20,3/9/20,3/10/20,3/11/20,3/12/20,3/13/20,3/14/20,3/15/20 +,Thailand,15,101,2,3,5,7,8,8,14,14,14,19,19,19,19,25,25,25,25,32,32,32,33,33,33,33,33,34,35,35,35,35,35,35,35,35,37,40,40,41,42,42,43,43,43,47,48,50,50,50,53,59,70,75,82,114 +,Japan,36,138,2,1,2,2,4,4,7,7,11,15,20,20,20,22,22,45,25,25,26,26,26,28,28,29,43,59,66,74,84,94,105,122,147,159,170,189,214,228,241,256,274,293,331,360,420,461,502,511,581,639,639,701,773,839 +,Singapore,1.2833,103.8333,0,1,3,3,4,5,7,7,10,13,16,18,18,24,28,28,30,33,40,45,47,50,58,67,72,75,77,81,84,84,85,85,89,89,91,93,93,93,102,106,108,110,110,117,130,138,150,150,160,178,178,200,212,226 +,Nepal,28.1667,84.25,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +,Malaysia,2.5,112.5,0,0,0,3,4,4,4,7,8,8,8,8,8,10,12,12,12,16,16,18,18,18,19,19,22,22,22,22,22,22,22,22,22,22,22,22,23,23,25,29,29,36,50,50,83,93,99,117,129,149,149,197,238,428 +British Columbia,Canada,49.2827,-123.1207,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,4,4,4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,9,12,13,21,21,27,32,32,39,46,64,64,73 +New South Wales,Australia,-33.8688,151.2093,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,6,6,13,22,22,26,28,38,48,55,65,65,92,112,134 +Victoria,Australia,-37.8136,144.9631,0,0,0,0,1,1,1,1,2,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,7,7,9,9,10,10,10,11,11,15,18,21,21,36,49,57 +Queensland,Australia,-28.0167,153.4,0,0,0,0,0,0,0,1,3,2,3,2,2,3,3,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,9,9,9,11,11,13,13,13,15,15,18,20,20,35,46,61 +,Cambodia,11.55,104.9167,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,5,7,7 diff --git a/tests/expected_output/data_confirmed.json b/tests/expected_output/data_confirmed.json new file mode 100644 index 00000000..149d6f8f --- /dev/null +++ b/tests/expected_output/data_confirmed.json @@ -0,0 +1 @@ +{"last_updated":"2020-03-17T10:02:01.285418Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"} diff --git a/tests/expected_output/data_deaths.json b/tests/expected_output/data_deaths.json new file mode 100644 index 00000000..48dc9cc2 --- /dev/null +++ b/tests/expected_output/data_deaths.json @@ -0,0 +1 @@ +{"last_updated":"2020-03-17T10:23:22.505550Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"} diff --git a/tests/expected_output/data_recovered.json b/tests/expected_output/data_recovered.json new file mode 100644 index 00000000..149d6f8f --- /dev/null +++ b/tests/expected_output/data_recovered.json @@ -0,0 +1 @@ +{"last_updated":"2020-03-17T10:02:01.285418Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"} diff --git a/tests/test_countrycodes.py b/tests/test_countrycodes.py new file mode 100644 index 00000000..2a312fa0 --- /dev/null +++ b/tests/test_countrycodes.py @@ -0,0 +1,23 @@ +import pytest + +from app.utils import countrycodes + +""" +Todo: + * Test cases for capturing of stdout/stderr +""" + +@pytest.mark.parametrize("country_name,expected_country_code", + [("Germany", "DE"), + ("Bolivia, Plurinational State of", "BO"), + ("Korea, Democratic People's Republic of", "KP"), + ("BlaBla", "XX")]) +def test_countrycodes_is_3166_1(country_name, expected_country_code): + assert countrycodes.country_code(country_name) == expected_country_code + +@pytest.mark.parametrize("country_name_synonym, expected_country_code", + [("Deutschland", "DE"), + ("Iran (Islamic Republic of)", "IR"), + ("British Virgin Islands", "VG")]) +def test_countrycodes_synonym(country_name_synonym, expected_country_code): + assert countrycodes.country_code(country_name_synonym) == expected_country_code diff --git a/tests/test_data.py b/tests/test_data.py new file mode 100644 index 00000000..392a07af --- /dev/null +++ b/tests/test_data.py @@ -0,0 +1,71 @@ +from unittest import mock +import pytest + +from app import data +from app.utils import date + +""" +Todo: + * More separation of test case `test_data_parsing` +""" + +def mocked_requests_get(*args, **kwargs): + class TestResponse: + def __init__(self, state): + self.text = self.read_file(state) + + def read_file(self, state): + """ + Mock HTTP GET-method and return text from file + """ + filepath = "tests/example_data/time_series_19-covid-{}.csv".format(state) + print("Try to read {}".format(filepath)) + with open(filepath, "r") as file: + return file.read() + + filename = args[0].split("/")[-1] + #clean up for token (e.g. Deaths) + filename = filename.split("-")[-1].replace(".csv", "") + + return TestResponse(filename) + +@pytest.mark.parametrize("state, datetime_str", + [("recovered", "2020-03-17T10:02:01.285418"), + ("deaths", "2020-03-17T10:23:22.505550"), + ("confirmed", "2020-03-17T10:02:01.285418")]) +@mock.patch('app.data.requests.get', side_effect=mocked_requests_get) +@mock.patch('app.data.datetime') +def test_data_parsing(mock_datetime, mock_get, state, datetime_str): + """`data.get_data` sets current datentime via `utcnow()` + Control datetime for testing + Mocked datetime based on `last_updated` of expected_output/data_{state}.json + #datetime value need to be equal due to caching + """ + mock_datetime.utcnow.return_value.isoformat.return_value = datetime_str + output = data.get_data(state) + + #simple schema validation + assert output["source"] == "https://github.com/ExpDev07/coronavirus-tracker-api" + assert isinstance(output["latest"], int) + #check for valid datestring + assert date.is_date(output["last_updated"]) is True + #ensure date formating + assert output["last_updated"] == datetime_str + "Z" + #validate location schema + location_entry = output["locations"][0] + + assert isinstance(location_entry["country"], str) + assert isinstance(location_entry["country_code"], str) + assert len(location_entry["country_code"]) == 2 + assert isinstance(location_entry["province"], str) + assert isinstance(location_entry["latest"], int) + + #validate coordinates in location + coordinates = location_entry["coordinates"] + assert isinstance(coordinates["lat"], str) + assert isinstance(coordinates["long"], str) + + #validate history in location + history = location_entry["history"] + assert date.is_date(list(history.keys())[0]) is True + assert isinstance(list(history.values())[0], int) diff --git a/tests/test_date.py b/tests/test_date.py new file mode 100644 index 00000000..b8af737b --- /dev/null +++ b/tests/test_date.py @@ -0,0 +1,19 @@ +import pytest + +from app.utils import date + + +@pytest.mark.parametrize("str_date, fuzzy_bool, expected_value", + [("1990-12-1", False, True), + ("2005/3", False, True), + ("Jan 19, 1990", False, True), + ("today is 2019-03-27", False, False), + ("Monday at 12:01am", False, True), + ("xyz_not_a_date", False, False), + ("yesterday", False, False), + ("today is 2019-03-27", True, True)]) +def test_is_date(str_date, fuzzy_bool, expected_value): + """ + Testdata from https://stackoverflow.com/a/25341965/7120095 + """ + assert date.is_date(str_date, fuzzy=fuzzy_bool) is expected_value diff --git a/tests/test_routes.py b/tests/test_routes.py new file mode 100644 index 00000000..b9d1d257 --- /dev/null +++ b/tests/test_routes.py @@ -0,0 +1,66 @@ +import unittest +from unittest import mock + +import app + +from .test_data import mocked_requests_get + + +@mock.patch('app.data.requests.get', side_effect=mocked_requests_get) +@mock.patch('app.data.datetime') +class FlaskRoutesTest(unittest.TestCase): + """ + Need to mock some objects to control testing data locally + """ + + #load app context only once + app = app.create_app() + + def setUp(self): + self.client = FlaskRoutesTest.app.test_client() + + def test_app_route_recovered(self, mock_datetime, mock_get): + """ + :param mock_datetime: mock.Mock, Mocking object for module path app.data.datetime + :param mock_get: mock.Mock, Mocking object for module path app.data.requests.get + """ + #mocked datetime based on `last_updated` of expected_output/data_{state}.json + #datetime value need to be equal due to caching + mock_datetime.utcnow.return_value.isoformat.return_value = "2020-03-17T10:02:01.285418" + state = "recovered" + filepath = "tests/expected_output/data_{state}.json".format(state=state) + with open(filepath, "r") as file: + expected_json_output = file.read() + + output_data = self.client.get("/{}".format(state)).data.decode() + + assert output_data == expected_json_output + + def test_app_route_deaths(self, mock_datetime, mock_get): + #mocked datetime based on `last_updated` of expected_output/data_{state}.json + #datetime value need to be equal due to caching + mock_datetime.utcnow.return_value.isoformat.return_value = "2020-03-17T10:23:22.505550" + state = "deaths" + filepath = "tests/expected_output/data_{state}.json".format(state=state) + with open(filepath, "r") as file: + expected_json_output = file.read() + + output_data = self.client.get("/{}".format(state)).data.decode() + + assert output_data == expected_json_output + + def test_app_route_confirmed(self, mock_datetime, mock_get): + #mocked datetime based on `last_updated` of expected_output/data_{state}.json + #datetime value need to be equal due to caching + mock_datetime.utcnow.return_value.isoformat.return_value = "2020-03-17T10:02:01.285418" + state = "confirmed" + filepath = "tests/expected_output/data_{state}.json".format(state=state) + with open(filepath, "r") as file: + expected_json_output = file.read() + + output_data = self.client.get("/{}".format(state)).data.decode() + + assert output_data == expected_json_output + + def tearDown(self): + pass From 7360337b63c09806045d5047cf612f620622c900 Mon Sep 17 00:00:00 2001 From: gribok <40306040+gribok@users.noreply.github.com> Date: Wed, 18 Mar 2020 14:47:57 +0000 Subject: [PATCH 2/4] merge v2 --- README.md | 93 ++++++++++++++++---- app/__init__.py | 3 +- app/{ => config}/settings.py | 0 app/coordinates.py | 20 +++++ app/data/__init__.py | 73 ---------------- app/location.py | 49 +++++++++++ app/models/location.py | 4 - app/routes/__init__.py | 9 +- app/routes/{ => v1}/all.py | 8 +- app/routes/{ => v1}/confirmed.py | 4 +- app/routes/{ => v1}/deaths.py | 4 +- app/routes/{ => v1}/recovered.py | 4 +- app/routes/v2/latest.py | 18 ++++ app/routes/v2/locations.py | 40 +++++++++ app/services/__init__.py | 4 + app/services/location/__init__.py | 26 ++++++ app/services/location/jhu.py | 137 ++++++++++++++++++++++++++++++ app/timeline.py | 33 +++++++ app/utils/countrycodes.py | 4 +- 19 files changed, 423 insertions(+), 110 deletions(-) rename app/{ => config}/settings.py (100%) create mode 100644 app/coordinates.py delete mode 100644 app/data/__init__.py create mode 100644 app/location.py delete mode 100644 app/models/location.py rename app/routes/{ => v1}/all.py (72%) rename app/routes/{ => v1}/confirmed.py (52%) rename app/routes/{ => v1}/deaths.py (52%) rename app/routes/{ => v1}/recovered.py (52%) create mode 100644 app/routes/v2/latest.py create mode 100644 app/routes/v2/locations.py create mode 100644 app/services/__init__.py create mode 100644 app/services/location/__init__.py create mode 100644 app/services/location/jhu.py create mode 100644 app/timeline.py diff --git a/README.md b/README.md index 3c024305..d0fb0b4e 100644 --- a/README.md +++ b/README.md @@ -12,37 +12,95 @@ ## Endpoints -All requests must be made to the base url: ``https://coronavirus-tracker-api.herokuapp.com`` (e.g: https://coronavirus-tracker-api.herokuapp.com/all). You can try them out in your browser to further inspect responses. +All requests must be made to the base url: ``https://coronavirus-tracker-api.herokuapp.com/v2/`` (e.g: https://coronavirus-tracker-api.herokuapp.com/v2/locations). You can try them out in your browser to further inspect responses. -Getting confirmed cases, deaths, and recoveries: +### Getting latest amount of total confirmed cases, deaths, and recoveries. ```http -GET /all +GET /v2/latest ``` ```json -{ "latest": { ... }, "confirmed": { ... }, "deaths": { ... }, "recovered": { ... } } +{ + "latest": { + "confirmed": 197146, + "deaths": 7905, + "recovered": 80840 + } +} ``` -Getting just confirmed: +### Getting all locations. ```http -GET /confirmed +GET /v2/locations ``` ```json { - "latest": 42767, - "locations": [ ... ], - "last_updated": "2020-03-07T18:08:58.432242Z", - "source": "https://github.com/ExpDev07/coronavirus-tracker-api" + "locations": [ + { + "id": 0, + "country": "Thailand", + "country_code": "TH", + "province": "", + "coordinates": { + "latitude": "15", + "longitude": "101" + }, + "latest": { + "confirmed": 177, + "deaths": 1, + "recovered": 41 + } + }, + { + "id": 39, + "country": "Norway", + "country_code": "NO", + "province": "", + "coordinates": { + "latitude": "60.472", + "longitude": "8.4689" + }, + "latest": { + "confirmed": 1463, + "deaths": 3, + "recovered": 1 + } + } + ] } ``` -Getting just deaths: +Additionally, you can also filter by country ([alpha-2 country_code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)). ```http -GET /deaths +GET /v2/locations?country_code=US ``` -Getting just recoveries: +### Getting a specific location (includes timeline). ```http -GET /recovered +GET /v2/locations/:id +``` +```json +{ + "location": { + "id": 39, + "country": "Norway", + "country_code": "NO", + "province": "", + "coordinates": { }, + "latest": { }, + "timelines": { + "confirmed": { + "latest": 1463, + "timeline": { + "2020-03-16T00:00:00Z": 1333, + "2020-03-17T00:00:00Z": 1463 + } + }, + "deaths": { }, + "recovered": { } + } + } + } +} ``` ## Data @@ -89,7 +147,7 @@ You will need the following things properly installed on your computer. ### Linting -* `pylint app/` +* `pylint app/` ### Building @@ -116,4 +174,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d ## License +<<<<<<< HEAD The data is available to the public strictly for educational and academic research purposes. Please link to this repo somewhere in your project if you can (not required) :). +======= +The data is available to the public strictly for educational and academic research purposes. Please link to this repo somewhere in your project :). + +>>>>>>> 75eaed76fc26be64fbffe6999be24208c3665b8d diff --git a/app/__init__.py b/app/__init__.py index dc2a691e..6414cb3e 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,6 +1,5 @@ from flask import Flask from flask_cors import CORS -from . import settings def create_app(): """ @@ -12,7 +11,7 @@ def create_app(): CORS(app) # Set app config from settings. - app.config.from_pyfile('settings.py'); + app.config.from_pyfile('config/settings.py'); with app.app_context(): # Import routes. diff --git a/app/settings.py b/app/config/settings.py similarity index 100% rename from app/settings.py rename to app/config/settings.py diff --git a/app/coordinates.py b/app/coordinates.py new file mode 100644 index 00000000..0243e637 --- /dev/null +++ b/app/coordinates.py @@ -0,0 +1,20 @@ +class Coordinates: + """ + A position on earth using decimal coordinates (latitude and longitude). + """ + + def __init__(self, latitude, longitude): + self.latitude = latitude + self.longitude = longitude + + def serialize(self): + """ + Serializes the coordinates into a dict. + """ + return { + 'latitude' : self.latitude, + 'longitude': self.longitude + } + + def __str__(self): + return 'lat: %s, long: %s' % (self.latitude, self.longitude) \ No newline at end of file diff --git a/app/data/__init__.py b/app/data/__init__.py deleted file mode 100644 index c3d5ffa1..00000000 --- a/app/data/__init__.py +++ /dev/null @@ -1,73 +0,0 @@ -import requests -import csv -from datetime import datetime -from cachetools import cached, TTLCache -from ..utils import countrycodes, date as date_util - -""" -Base URL for fetching data. -""" -base_url = 'https://raw.githubusercontent.com/CSSEGISandData/2019-nCoV/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-%s.csv'; - -@cached(cache=TTLCache(maxsize=1024, ttl=3600)) -def get_data(category): - """ - Retrieves the data for the provided type. The data is cached for 1 hour. - """ - - # Adhere to category naming standard. - category = category.lower().capitalize(); - - # Request the data - request = requests.get(base_url % category) - text = request.text - - # Parse the CSV. - data = list(csv.DictReader(text.splitlines())) - - # The normalized locations. - locations = [] - - for item in data: - # Filter out all the dates. - dates = dict(filter(lambda element: date_util.is_date(element[0]), item.items())) - - # Make location history from dates. - history = { date: int(amount or 0) for date, amount in dates.items() }; - - # Country for this location. - country = item['Country/Region'] - - # Latest data insert value. - latest = list(history.values())[-1]; - - # Normalize the item and append to locations. - locations.append({ - # General info. - 'country': country, - 'country_code': countrycodes.country_code(country), - 'province': item['Province/State'], - - # Coordinates. - 'coordinates': { - 'lat': item['Lat'], - 'long': item['Long'], - }, - - # History. - 'history': history, - - # Latest statistic. - 'latest': int(latest or 0), - }) - - # Latest total. - latest = sum(map(lambda location: location['latest'], locations)) - - # Return the final data. - return { - 'locations': locations, - 'latest': latest, - 'last_updated': datetime.utcnow().isoformat() + 'Z', - 'source': 'https://github.com/ExpDev07/coronavirus-tracker-api', - } diff --git a/app/location.py b/app/location.py new file mode 100644 index 00000000..e348c697 --- /dev/null +++ b/app/location.py @@ -0,0 +1,49 @@ +from .coordinates import Coordinates +from .utils import countrycodes + +class Location: + """ + A location in the world affected by the coronavirus. + """ + + def __init__(self, id, country, province, coordinates, confirmed, deaths, recovered): + # General info. + self.id = id + self.country = country.strip() + self.province = province.strip() + self.coordinates = coordinates + + # Data. + self.confirmed = confirmed + self.deaths = deaths + self.recovered = recovered + + + @property + def country_code(self): + """ + Gets the alpha-2 code represention of the country. Returns 'XX' if none is found. + """ + return (countrycodes.country_code(self.country) or countrycodes.default_code).upper() + + def serialize(self): + """ + Serializes the location into a dict. + """ + return { + # General info. + 'id' : self.id, + 'country' : self.country, + 'province' : self.province, + 'country_code': self.country_code, + + # Coordinates. + 'coordinates': self.coordinates.serialize(), + + # Latest data. + 'latest': { + 'confirmed': self.confirmed.latest, + 'deaths' : self.deaths.latest, + 'recovered': self.recovered.latest + } + } \ No newline at end of file diff --git a/app/models/location.py b/app/models/location.py deleted file mode 100644 index 5f202b3c..00000000 --- a/app/models/location.py +++ /dev/null @@ -1,4 +0,0 @@ -class Location(): - """ - A location in the world affected by the coronavirus. - """ \ No newline at end of file diff --git a/app/routes/__init__.py b/app/routes/__init__.py index 0e2e3c2c..b2bc5b73 100644 --- a/app/routes/__init__.py +++ b/app/routes/__init__.py @@ -1,4 +1,5 @@ -from . import confirmed -from . import deaths -from . import recovered -from . import all \ No newline at end of file +# API version 1. +from .v1 import confirmed, deaths, recovered, all + +# API version 2. +from .v2 import locations, latest \ No newline at end of file diff --git a/app/routes/all.py b/app/routes/v1/all.py similarity index 72% rename from app/routes/all.py rename to app/routes/v1/all.py index f80e289f..735b4d10 100644 --- a/app/routes/all.py +++ b/app/routes/v1/all.py @@ -1,13 +1,13 @@ from flask import jsonify from flask import current_app as app -from ..data import get_data +from ...services.location.jhu import get_category @app.route('/all') def all(): # Get all the categories. - confirmed = get_data('confirmed') - deaths = get_data('deaths') - recovered = get_data('recovered') + confirmed = get_category('confirmed') + deaths = get_category('deaths') + recovered = get_category('recovered') return jsonify({ # Data. diff --git a/app/routes/confirmed.py b/app/routes/v1/confirmed.py similarity index 52% rename from app/routes/confirmed.py rename to app/routes/v1/confirmed.py index dfa3346d..52fcf7e0 100644 --- a/app/routes/confirmed.py +++ b/app/routes/v1/confirmed.py @@ -1,7 +1,7 @@ from flask import jsonify from flask import current_app as app -from ..data import get_data +from ...services.location.jhu import get_category @app.route('/confirmed') def confirmed(): - return jsonify(get_data('confirmed')) \ No newline at end of file + return jsonify(get_category('confirmed')) \ No newline at end of file diff --git a/app/routes/deaths.py b/app/routes/v1/deaths.py similarity index 52% rename from app/routes/deaths.py rename to app/routes/v1/deaths.py index 61ef7546..76913b6d 100644 --- a/app/routes/deaths.py +++ b/app/routes/v1/deaths.py @@ -1,7 +1,7 @@ from flask import jsonify from flask import current_app as app -from ..data import get_data +from ...services.location.jhu import get_category @app.route('/deaths') def deaths(): - return jsonify(get_data('deaths')) \ No newline at end of file + return jsonify(get_category('deaths')) \ No newline at end of file diff --git a/app/routes/recovered.py b/app/routes/v1/recovered.py similarity index 52% rename from app/routes/recovered.py rename to app/routes/v1/recovered.py index 1abdef26..ded8eb7c 100644 --- a/app/routes/recovered.py +++ b/app/routes/v1/recovered.py @@ -1,7 +1,7 @@ from flask import jsonify from flask import current_app as app -from ..data import get_data +from ...services.location.jhu import get_category @app.route('/recovered') def recovered(): - return jsonify(get_data('recovered')) \ No newline at end of file + return jsonify(get_category('recovered')) \ No newline at end of file diff --git a/app/routes/v2/latest.py b/app/routes/v2/latest.py new file mode 100644 index 00000000..0f3ba265 --- /dev/null +++ b/app/routes/v2/latest.py @@ -0,0 +1,18 @@ +from flask import jsonify, current_app as app +from ...services import jhu + +@app.route('/v2/latest') +def latest(): + # Get the serialized version of all the locations. + locations = [ location.serialize() for location in jhu.get_all() ] + + # All the latest information. + latest = list(map(lambda location: location['latest'], locations)) + + return jsonify({ + 'latest': { + 'confirmed': sum(map(lambda latest: latest['confirmed'], latest)), + 'deaths' : sum(map(lambda latest: latest['deaths'], latest)), + 'recovered': sum(map(lambda latest: latest['recovered'], latest)), + } + }) \ No newline at end of file diff --git a/app/routes/v2/locations.py b/app/routes/v2/locations.py new file mode 100644 index 00000000..eb50e251 --- /dev/null +++ b/app/routes/v2/locations.py @@ -0,0 +1,40 @@ +from flask import jsonify, request, current_app as app +from ...services import jhu + +@app.route('/v2/locations') +def locations(): + # Query parameters. + country_code = request.args.get('country_code', type=str) + + # Retrieve all the locations. + locations = jhu.get_all() + + # Filtering my country code if provided. + if not country_code is None: + locations = list(filter(lambda location: location.country_code == country_code.upper(), locations)) + + # Serialize each location and return. + return jsonify({ + 'locations': [ + location.serialize() for location in locations + ] + }) + +@app.route('/v2/locations/') +def location(id): + # Retrieve location with the provided id. + location = jhu.get(id) + + # Get all the timelines. + timelines = { + 'confirmed': location.confirmed.serialize(), + 'deaths' : location.deaths.serialize(), + 'recovered': location.recovered.serialize(), + } + + # Serialize the location, add timelines, and then return. + return jsonify({ + 'location': { + **jhu.get(id).serialize(), **{ 'timelines': timelines } + } + }) \ No newline at end of file diff --git a/app/services/__init__.py b/app/services/__init__.py new file mode 100644 index 00000000..0c5b206c --- /dev/null +++ b/app/services/__init__.py @@ -0,0 +1,4 @@ +from .location.jhu import JhuLocationService + +# Instances of the services. +jhu = JhuLocationService() \ No newline at end of file diff --git a/app/services/location/__init__.py b/app/services/location/__init__.py new file mode 100644 index 00000000..3338b3d3 --- /dev/null +++ b/app/services/location/__init__.py @@ -0,0 +1,26 @@ +from abc import ABC, abstractmethod + +class LocationService(ABC): + """ + Service for retrieving locations. + """ + + @abstractmethod + def get_all(self): + """ + Gets and returns all of the locations. + + :returns: The locations. + :rtype: List[Location] + """ + raise NotImplementedError + + @abstractmethod + def get(self, id): + """ + Gets and returns location with the provided id. + + :returns: The location. + :rtype: Location + """ + raise NotImplementedError \ No newline at end of file diff --git a/app/services/location/jhu.py b/app/services/location/jhu.py new file mode 100644 index 00000000..621c56ca --- /dev/null +++ b/app/services/location/jhu.py @@ -0,0 +1,137 @@ +from . import LocationService +from ...location import Location +from ...coordinates import Coordinates +from ...timeline import Timeline + +class JhuLocationService(LocationService): + """ + Service for retrieving locations from Johns Hopkins CSSE (https://github.com/CSSEGISandData/COVID-19). + """ + + def get_all(self): + # Get the locations. + return get_locations() + + def get(self, id): + # Get location at the index equal to provided id. + return self.get_all()[id] + +import requests +import csv +from datetime import datetime +from cachetools import cached, TTLCache +from ...utils import countrycodes, date as date_util + +""" +Base URL for fetching category. +""" +base_url = 'https://raw.githubusercontent.com/CSSEGISandData/2019-nCoV/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-%s.csv'; + +@cached(cache=TTLCache(maxsize=1024, ttl=3600)) +def get_category(category): + """ + Retrieves the data for the provided category. The data is cached for 1 hour. + + :returns: The data for category. + :rtype: dict + """ + + # Adhere to category naming standard. + category = category.lower().capitalize(); + + # Request the data + request = requests.get(base_url % category) + text = request.text + + # Parse the CSV. + data = list(csv.DictReader(text.splitlines())) + + # The normalized locations. + locations = [] + + for item in data: + # Filter out all the dates. + dates = dict(filter(lambda element: date_util.is_date(element[0]), item.items())) + + # Make location history from dates. + history = { date: int(amount or 0) for date, amount in dates.items() }; + + # Country for this location. + country = item['Country/Region'] + + # Latest data insert value. + latest = list(history.values())[-1]; + + # Normalize the item and append to locations. + locations.append({ + # General info. + 'country': country, + 'country_code': countrycodes.country_code(country), + 'province': item['Province/State'], + + # Coordinates. + 'coordinates': { + 'lat': item['Lat'], + 'long': item['Long'], + }, + + # History. + 'history': history, + + # Latest statistic. + 'latest': int(latest or 0), + }) + + # Latest total. + latest = sum(map(lambda location: location['latest'], locations)) + + # Return the final data. + return { + 'locations': locations, + 'latest': latest, + 'last_updated': datetime.utcnow().isoformat() + 'Z', + 'source': 'https://github.com/ExpDev07/coronavirus-tracker-api', + } + +@cached(cache=TTLCache(maxsize=1024, ttl=3600)) +def get_locations(): + """ + Retrieves the locations from the categories. The locations are cached for 1 hour. + + :returns: The locations. + :rtype: List[Location] + """ + # Get all of the data categories locations. + confirmed = get_category('confirmed')['locations'] + deaths = get_category('deaths')['locations'] + recovered = get_category('recovered')['locations'] + + # Final locations to return. + locations = [] + + # Go through locations. + for index, location in enumerate(confirmed): + # Get the timelines. + timelines = { + 'confirmed' : confirmed[index]['history'], + 'deaths' : deaths[index]['history'], + 'recovered' : recovered[index]['history'], + } + + # Grab coordinates. + coordinates = location['coordinates'] + + # Create location and append. + locations.append(Location( + # General info. + index, location['country'], location['province'], Coordinates(coordinates['lat'], coordinates['long']), + + # Timelines (parse dates as ISO). + Timeline({ datetime.strptime(date, '%m/%d/%y').isoformat() + 'Z': amount for date, amount in timelines['confirmed'].items() }), + Timeline({ datetime.strptime(date, '%m/%d/%y').isoformat() + 'Z': amount for date, amount in timelines['deaths'].items() }), + Timeline({ datetime.strptime(date, '%m/%d/%y').isoformat() + 'Z': amount for date, amount in timelines['recovered'].items() }) + )) + + # Finally, return the locations. + return locations + \ No newline at end of file diff --git a/app/timeline.py b/app/timeline.py new file mode 100644 index 00000000..48af1ac5 --- /dev/null +++ b/app/timeline.py @@ -0,0 +1,33 @@ +from datetime import datetime +from collections import OrderedDict + +class Timeline: + """ + Timeline with history of data. + """ + + def __init__(self, history = {}): + self.__timeline = history + + @property + def timeline(self): + """ + Gets the history sorted by date (key). + """ + return OrderedDict(sorted(self.__timeline.items())) + + @property + def latest(self): + """ + Gets the latest available history value. + """ + return list(self.timeline.values())[-1] or 0 + + def serialize(self): + """ + Serializes the data into a dict. + """ + return { + 'latest' : self.latest, + 'timeline': self.timeline + } \ No newline at end of file diff --git a/app/utils/countrycodes.py b/app/utils/countrycodes.py index 09d20076..4215d62c 100644 --- a/app/utils/countrycodes.py +++ b/app/utils/countrycodes.py @@ -339,14 +339,14 @@ "Congo (Brazzaville)" : "Congo", "Deutschland" : "Germany", "The Bahamas" : "Bahamas", + "The Gambia" : "Gambia", # "Others" has no mapping, i.e. the default val is used # "Cruise Ship" has no mapping, i.e. the default val is used } def country_code(country): """ - Return two letter country code (Alpha-2) according to - https://en.wikipedia.org/wiki/ISO_3166-1 + Return two letter country code (Alpha-2) according to https://en.wikipedia.org/wiki/ISO_3166-1 Defaults to "XX". """ if country in is_3166_1: From 841d0c29d1c367ee3221d3249126d7bc86ef68db Mon Sep 17 00:00:00 2001 From: gribok <40306040+gribok@users.noreply.github.com> Date: Wed, 18 Mar 2020 21:48:17 +0000 Subject: [PATCH 3/4] adapt testsuite to /v2. See ExpDev07/coronavirus-tracker-api#65 --- app/routes/v2/locations.py | 2 +- tests/expected_output/v1_all.json | 1 + .../{data_deaths.json => v1_confirmed.json} | 0 .../{data_confirmed.json => v1_deaths.json} | 2 +- ...{data_recovered.json => v1_recovered.json} | 2 +- tests/expected_output/v2_locations.json | 1 + tests/expected_output/v2_locations_id_1.json | 1 + tests/test_coordinates.py | 19 +++ tests/test_data.py | 71 --------- tests/test_jhu.py | 145 ++++++++++++++++++ tests/test_location.py | 44 ++++++ tests/test_routes.py | 115 +++++++++----- tests/test_timeline.py | 30 ++++ 13 files changed, 324 insertions(+), 109 deletions(-) create mode 100644 tests/expected_output/v1_all.json rename tests/expected_output/{data_deaths.json => v1_confirmed.json} (100%) rename tests/expected_output/{data_confirmed.json => v1_deaths.json} (99%) rename tests/expected_output/{data_recovered.json => v1_recovered.json} (99%) create mode 100644 tests/expected_output/v2_locations.json create mode 100644 tests/expected_output/v2_locations_id_1.json create mode 100644 tests/test_coordinates.py delete mode 100644 tests/test_data.py create mode 100644 tests/test_jhu.py create mode 100644 tests/test_location.py create mode 100644 tests/test_timeline.py diff --git a/app/routes/v2/locations.py b/app/routes/v2/locations.py index eb50e251..bacf7b19 100644 --- a/app/routes/v2/locations.py +++ b/app/routes/v2/locations.py @@ -37,4 +37,4 @@ def location(id): 'location': { **jhu.get(id).serialize(), **{ 'timelines': timelines } } - }) \ No newline at end of file + }) diff --git a/tests/expected_output/v1_all.json b/tests/expected_output/v1_all.json new file mode 100644 index 00000000..5ec413a0 --- /dev/null +++ b/tests/expected_output/v1_all.json @@ -0,0 +1 @@ +{"confirmed":{"last_updated":"2020-03-17T10:23:22.505550Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"},"deaths":{"last_updated":"2020-03-17T10:23:22.505550Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"},"latest":{"confirmed":1940,"deaths":1940,"recovered":1940},"recovered":{"last_updated":"2020-03-17T10:23:22.505550Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"}} diff --git a/tests/expected_output/data_deaths.json b/tests/expected_output/v1_confirmed.json similarity index 100% rename from tests/expected_output/data_deaths.json rename to tests/expected_output/v1_confirmed.json diff --git a/tests/expected_output/data_confirmed.json b/tests/expected_output/v1_deaths.json similarity index 99% rename from tests/expected_output/data_confirmed.json rename to tests/expected_output/v1_deaths.json index 149d6f8f..48dc9cc2 100644 --- a/tests/expected_output/data_confirmed.json +++ b/tests/expected_output/v1_deaths.json @@ -1 +1 @@ -{"last_updated":"2020-03-17T10:02:01.285418Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"} +{"last_updated":"2020-03-17T10:23:22.505550Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"} diff --git a/tests/expected_output/data_recovered.json b/tests/expected_output/v1_recovered.json similarity index 99% rename from tests/expected_output/data_recovered.json rename to tests/expected_output/v1_recovered.json index 149d6f8f..48dc9cc2 100644 --- a/tests/expected_output/data_recovered.json +++ b/tests/expected_output/v1_recovered.json @@ -1 +1 @@ -{"last_updated":"2020-03-17T10:02:01.285418Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"} +{"last_updated":"2020-03-17T10:23:22.505550Z","latest":1940,"locations":[{"coordinates":{"lat":"15","long":"101"},"country":"Thailand","country_code":"TH","history":{"1/22/20":2,"1/23/20":3,"1/24/20":5,"1/25/20":7,"1/26/20":8,"1/27/20":8,"1/28/20":14,"1/29/20":14,"1/30/20":14,"1/31/20":19,"2/1/20":19,"2/10/20":32,"2/11/20":33,"2/12/20":33,"2/13/20":33,"2/14/20":33,"2/15/20":33,"2/16/20":34,"2/17/20":35,"2/18/20":35,"2/19/20":35,"2/2/20":19,"2/20/20":35,"2/21/20":35,"2/22/20":35,"2/23/20":35,"2/24/20":35,"2/25/20":37,"2/26/20":40,"2/27/20":40,"2/28/20":41,"2/29/20":42,"2/3/20":19,"2/4/20":25,"2/5/20":25,"2/6/20":25,"2/7/20":25,"2/8/20":32,"2/9/20":32,"3/1/20":42,"3/10/20":53,"3/11/20":59,"3/12/20":70,"3/13/20":75,"3/14/20":82,"3/15/20":114,"3/2/20":43,"3/3/20":43,"3/4/20":43,"3/5/20":47,"3/6/20":48,"3/7/20":50,"3/8/20":50,"3/9/20":50},"latest":114,"province":""},{"coordinates":{"lat":"36","long":"138"},"country":"Japan","country_code":"JP","history":{"1/22/20":2,"1/23/20":1,"1/24/20":2,"1/25/20":2,"1/26/20":4,"1/27/20":4,"1/28/20":7,"1/29/20":7,"1/30/20":11,"1/31/20":15,"2/1/20":20,"2/10/20":26,"2/11/20":26,"2/12/20":28,"2/13/20":28,"2/14/20":29,"2/15/20":43,"2/16/20":59,"2/17/20":66,"2/18/20":74,"2/19/20":84,"2/2/20":20,"2/20/20":94,"2/21/20":105,"2/22/20":122,"2/23/20":147,"2/24/20":159,"2/25/20":170,"2/26/20":189,"2/27/20":214,"2/28/20":228,"2/29/20":241,"2/3/20":20,"2/4/20":22,"2/5/20":22,"2/6/20":45,"2/7/20":25,"2/8/20":25,"2/9/20":26,"3/1/20":256,"3/10/20":581,"3/11/20":639,"3/12/20":639,"3/13/20":701,"3/14/20":773,"3/15/20":839,"3/2/20":274,"3/3/20":293,"3/4/20":331,"3/5/20":360,"3/6/20":420,"3/7/20":461,"3/8/20":502,"3/9/20":511},"latest":839,"province":""},{"coordinates":{"lat":"1.2833","long":"103.8333"},"country":"Singapore","country_code":"SG","history":{"1/22/20":0,"1/23/20":1,"1/24/20":3,"1/25/20":3,"1/26/20":4,"1/27/20":5,"1/28/20":7,"1/29/20":7,"1/30/20":10,"1/31/20":13,"2/1/20":16,"2/10/20":45,"2/11/20":47,"2/12/20":50,"2/13/20":58,"2/14/20":67,"2/15/20":72,"2/16/20":75,"2/17/20":77,"2/18/20":81,"2/19/20":84,"2/2/20":18,"2/20/20":84,"2/21/20":85,"2/22/20":85,"2/23/20":89,"2/24/20":89,"2/25/20":91,"2/26/20":93,"2/27/20":93,"2/28/20":93,"2/29/20":102,"2/3/20":18,"2/4/20":24,"2/5/20":28,"2/6/20":28,"2/7/20":30,"2/8/20":33,"2/9/20":40,"3/1/20":106,"3/10/20":160,"3/11/20":178,"3/12/20":178,"3/13/20":200,"3/14/20":212,"3/15/20":226,"3/2/20":108,"3/3/20":110,"3/4/20":110,"3/5/20":117,"3/6/20":130,"3/7/20":138,"3/8/20":150,"3/9/20":150},"latest":226,"province":""},{"coordinates":{"lat":"28.1667","long":"84.25"},"country":"Nepal","country_code":"NP","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":1,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":1,"3/11/20":1,"3/12/20":1,"3/13/20":1,"3/14/20":1,"3/15/20":1,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":1,"3/9/20":1},"latest":1,"province":""},{"coordinates":{"lat":"2.5","long":"112.5"},"country":"Malaysia","country_code":"MY","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":3,"1/26/20":4,"1/27/20":4,"1/28/20":4,"1/29/20":7,"1/30/20":8,"1/31/20":8,"2/1/20":8,"2/10/20":18,"2/11/20":18,"2/12/20":18,"2/13/20":19,"2/14/20":19,"2/15/20":22,"2/16/20":22,"2/17/20":22,"2/18/20":22,"2/19/20":22,"2/2/20":8,"2/20/20":22,"2/21/20":22,"2/22/20":22,"2/23/20":22,"2/24/20":22,"2/25/20":22,"2/26/20":22,"2/27/20":23,"2/28/20":23,"2/29/20":25,"2/3/20":8,"2/4/20":10,"2/5/20":12,"2/6/20":12,"2/7/20":12,"2/8/20":16,"2/9/20":16,"3/1/20":29,"3/10/20":129,"3/11/20":149,"3/12/20":149,"3/13/20":197,"3/14/20":238,"3/15/20":428,"3/2/20":29,"3/3/20":36,"3/4/20":50,"3/5/20":50,"3/6/20":83,"3/7/20":93,"3/8/20":99,"3/9/20":117},"latest":428,"province":""},{"coordinates":{"lat":"49.2827","long":"-123.1207"},"country":"Canada","country_code":"CA","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":1,"2/20/20":5,"2/21/20":6,"2/22/20":6,"2/23/20":6,"2/24/20":6,"2/25/20":7,"2/26/20":7,"2/27/20":7,"2/28/20":7,"2/29/20":8,"2/3/20":1,"2/4/20":1,"2/5/20":2,"2/6/20":2,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":8,"3/10/20":32,"3/11/20":39,"3/12/20":46,"3/13/20":64,"3/14/20":64,"3/15/20":73,"3/2/20":8,"3/3/20":9,"3/4/20":12,"3/5/20":13,"3/6/20":21,"3/7/20":21,"3/8/20":27,"3/9/20":32},"latest":73,"province":"British Columbia"},{"coordinates":{"lat":"-33.8688","long":"151.2093"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":3,"1/27/20":4,"1/28/20":4,"1/29/20":4,"1/30/20":4,"1/31/20":4,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":4,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":6,"3/10/20":55,"3/11/20":65,"3/12/20":65,"3/13/20":92,"3/14/20":112,"3/15/20":134,"3/2/20":6,"3/3/20":13,"3/4/20":22,"3/5/20":22,"3/6/20":26,"3/7/20":28,"3/8/20":38,"3/9/20":48},"latest":134,"province":"New South Wales"},{"coordinates":{"lat":"-37.8136","long":"144.9631"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":1,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":2,"1/31/20":3,"2/1/20":4,"2/10/20":4,"2/11/20":4,"2/12/20":4,"2/13/20":4,"2/14/20":4,"2/15/20":4,"2/16/20":4,"2/17/20":4,"2/18/20":4,"2/19/20":4,"2/2/20":4,"2/20/20":4,"2/21/20":4,"2/22/20":4,"2/23/20":4,"2/24/20":4,"2/25/20":4,"2/26/20":4,"2/27/20":4,"2/28/20":4,"2/29/20":7,"2/3/20":4,"2/4/20":4,"2/5/20":4,"2/6/20":4,"2/7/20":4,"2/8/20":4,"2/9/20":4,"3/1/20":7,"3/10/20":18,"3/11/20":21,"3/12/20":21,"3/13/20":36,"3/14/20":49,"3/15/20":57,"3/2/20":9,"3/3/20":9,"3/4/20":10,"3/5/20":10,"3/6/20":10,"3/7/20":11,"3/8/20":11,"3/9/20":15},"latest":57,"province":"Victoria"},{"coordinates":{"lat":"-28.0167","long":"153.4"},"country":"Australia","country_code":"AU","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":0,"1/28/20":0,"1/29/20":1,"1/30/20":3,"1/31/20":2,"2/1/20":3,"2/10/20":5,"2/11/20":5,"2/12/20":5,"2/13/20":5,"2/14/20":5,"2/15/20":5,"2/16/20":5,"2/17/20":5,"2/18/20":5,"2/19/20":5,"2/2/20":2,"2/20/20":5,"2/21/20":5,"2/22/20":5,"2/23/20":5,"2/24/20":5,"2/25/20":5,"2/26/20":5,"2/27/20":5,"2/28/20":5,"2/29/20":9,"2/3/20":2,"2/4/20":3,"2/5/20":3,"2/6/20":4,"2/7/20":5,"2/8/20":5,"2/9/20":5,"3/1/20":9,"3/10/20":18,"3/11/20":20,"3/12/20":20,"3/13/20":35,"3/14/20":46,"3/15/20":61,"3/2/20":9,"3/3/20":11,"3/4/20":11,"3/5/20":13,"3/6/20":13,"3/7/20":13,"3/8/20":15,"3/9/20":15},"latest":61,"province":"Queensland"},{"coordinates":{"lat":"11.55","long":"104.9167"},"country":"Cambodia","country_code":"KH","history":{"1/22/20":0,"1/23/20":0,"1/24/20":0,"1/25/20":0,"1/26/20":0,"1/27/20":1,"1/28/20":1,"1/29/20":1,"1/30/20":1,"1/31/20":1,"2/1/20":1,"2/10/20":1,"2/11/20":1,"2/12/20":1,"2/13/20":1,"2/14/20":1,"2/15/20":1,"2/16/20":1,"2/17/20":1,"2/18/20":1,"2/19/20":1,"2/2/20":1,"2/20/20":1,"2/21/20":1,"2/22/20":1,"2/23/20":1,"2/24/20":1,"2/25/20":1,"2/26/20":1,"2/27/20":1,"2/28/20":1,"2/29/20":1,"2/3/20":1,"2/4/20":1,"2/5/20":1,"2/6/20":1,"2/7/20":1,"2/8/20":1,"2/9/20":1,"3/1/20":1,"3/10/20":2,"3/11/20":3,"3/12/20":3,"3/13/20":5,"3/14/20":7,"3/15/20":7,"3/2/20":1,"3/3/20":1,"3/4/20":1,"3/5/20":1,"3/6/20":1,"3/7/20":1,"3/8/20":2,"3/9/20":2},"latest":7,"province":""}],"source":"https://github.com/ExpDev07/coronavirus-tracker-api"} diff --git a/tests/expected_output/v2_locations.json b/tests/expected_output/v2_locations.json new file mode 100644 index 00000000..e67d3f27 --- /dev/null +++ b/tests/expected_output/v2_locations.json @@ -0,0 +1 @@ +{"locations":[{"coordinates":{"latitude":"15","longitude":"101"},"country":"Thailand","country_code":"TH","id":0,"latest":{"confirmed":114,"deaths":114,"recovered":114},"province":""},{"coordinates":{"latitude":"36","longitude":"138"},"country":"Japan","country_code":"JP","id":1,"latest":{"confirmed":839,"deaths":839,"recovered":839},"province":""},{"coordinates":{"latitude":"1.2833","longitude":"103.8333"},"country":"Singapore","country_code":"SG","id":2,"latest":{"confirmed":226,"deaths":226,"recovered":226},"province":""},{"coordinates":{"latitude":"28.1667","longitude":"84.25"},"country":"Nepal","country_code":"NP","id":3,"latest":{"confirmed":1,"deaths":1,"recovered":1},"province":""},{"coordinates":{"latitude":"2.5","longitude":"112.5"},"country":"Malaysia","country_code":"MY","id":4,"latest":{"confirmed":428,"deaths":428,"recovered":428},"province":""},{"coordinates":{"latitude":"49.2827","longitude":"-123.1207"},"country":"Canada","country_code":"CA","id":5,"latest":{"confirmed":73,"deaths":73,"recovered":73},"province":"British Columbia"},{"coordinates":{"latitude":"-33.8688","longitude":"151.2093"},"country":"Australia","country_code":"AU","id":6,"latest":{"confirmed":134,"deaths":134,"recovered":134},"province":"New South Wales"},{"coordinates":{"latitude":"-37.8136","longitude":"144.9631"},"country":"Australia","country_code":"AU","id":7,"latest":{"confirmed":57,"deaths":57,"recovered":57},"province":"Victoria"},{"coordinates":{"latitude":"-28.0167","longitude":"153.4"},"country":"Australia","country_code":"AU","id":8,"latest":{"confirmed":61,"deaths":61,"recovered":61},"province":"Queensland"},{"coordinates":{"latitude":"11.55","longitude":"104.9167"},"country":"Cambodia","country_code":"KH","id":9,"latest":{"confirmed":7,"deaths":7,"recovered":7},"province":""}]} diff --git a/tests/expected_output/v2_locations_id_1.json b/tests/expected_output/v2_locations_id_1.json new file mode 100644 index 00000000..c78c4e0c --- /dev/null +++ b/tests/expected_output/v2_locations_id_1.json @@ -0,0 +1 @@ +{"location":{"coordinates":{"latitude":"36","longitude":"138"},"country":"Japan","country_code":"JP","id":1,"latest":{"confirmed":839,"deaths":839,"recovered":839},"province":"","timelines":{"confirmed":{"latest":839,"timeline":{"2020-01-22T00:00:00Z":2,"2020-01-23T00:00:00Z":1,"2020-01-24T00:00:00Z":2,"2020-01-25T00:00:00Z":2,"2020-01-26T00:00:00Z":4,"2020-01-27T00:00:00Z":4,"2020-01-28T00:00:00Z":7,"2020-01-29T00:00:00Z":7,"2020-01-30T00:00:00Z":11,"2020-01-31T00:00:00Z":15,"2020-02-01T00:00:00Z":20,"2020-02-02T00:00:00Z":20,"2020-02-03T00:00:00Z":20,"2020-02-04T00:00:00Z":22,"2020-02-05T00:00:00Z":22,"2020-02-06T00:00:00Z":45,"2020-02-07T00:00:00Z":25,"2020-02-08T00:00:00Z":25,"2020-02-09T00:00:00Z":26,"2020-02-10T00:00:00Z":26,"2020-02-11T00:00:00Z":26,"2020-02-12T00:00:00Z":28,"2020-02-13T00:00:00Z":28,"2020-02-14T00:00:00Z":29,"2020-02-15T00:00:00Z":43,"2020-02-16T00:00:00Z":59,"2020-02-17T00:00:00Z":66,"2020-02-18T00:00:00Z":74,"2020-02-19T00:00:00Z":84,"2020-02-20T00:00:00Z":94,"2020-02-21T00:00:00Z":105,"2020-02-22T00:00:00Z":122,"2020-02-23T00:00:00Z":147,"2020-02-24T00:00:00Z":159,"2020-02-25T00:00:00Z":170,"2020-02-26T00:00:00Z":189,"2020-02-27T00:00:00Z":214,"2020-02-28T00:00:00Z":228,"2020-02-29T00:00:00Z":241,"2020-03-01T00:00:00Z":256,"2020-03-02T00:00:00Z":274,"2020-03-03T00:00:00Z":293,"2020-03-04T00:00:00Z":331,"2020-03-05T00:00:00Z":360,"2020-03-06T00:00:00Z":420,"2020-03-07T00:00:00Z":461,"2020-03-08T00:00:00Z":502,"2020-03-09T00:00:00Z":511,"2020-03-10T00:00:00Z":581,"2020-03-11T00:00:00Z":639,"2020-03-12T00:00:00Z":639,"2020-03-13T00:00:00Z":701,"2020-03-14T00:00:00Z":773,"2020-03-15T00:00:00Z":839}},"deaths":{"latest":839,"timeline":{"2020-01-22T00:00:00Z":2,"2020-01-23T00:00:00Z":1,"2020-01-24T00:00:00Z":2,"2020-01-25T00:00:00Z":2,"2020-01-26T00:00:00Z":4,"2020-01-27T00:00:00Z":4,"2020-01-28T00:00:00Z":7,"2020-01-29T00:00:00Z":7,"2020-01-30T00:00:00Z":11,"2020-01-31T00:00:00Z":15,"2020-02-01T00:00:00Z":20,"2020-02-02T00:00:00Z":20,"2020-02-03T00:00:00Z":20,"2020-02-04T00:00:00Z":22,"2020-02-05T00:00:00Z":22,"2020-02-06T00:00:00Z":45,"2020-02-07T00:00:00Z":25,"2020-02-08T00:00:00Z":25,"2020-02-09T00:00:00Z":26,"2020-02-10T00:00:00Z":26,"2020-02-11T00:00:00Z":26,"2020-02-12T00:00:00Z":28,"2020-02-13T00:00:00Z":28,"2020-02-14T00:00:00Z":29,"2020-02-15T00:00:00Z":43,"2020-02-16T00:00:00Z":59,"2020-02-17T00:00:00Z":66,"2020-02-18T00:00:00Z":74,"2020-02-19T00:00:00Z":84,"2020-02-20T00:00:00Z":94,"2020-02-21T00:00:00Z":105,"2020-02-22T00:00:00Z":122,"2020-02-23T00:00:00Z":147,"2020-02-24T00:00:00Z":159,"2020-02-25T00:00:00Z":170,"2020-02-26T00:00:00Z":189,"2020-02-27T00:00:00Z":214,"2020-02-28T00:00:00Z":228,"2020-02-29T00:00:00Z":241,"2020-03-01T00:00:00Z":256,"2020-03-02T00:00:00Z":274,"2020-03-03T00:00:00Z":293,"2020-03-04T00:00:00Z":331,"2020-03-05T00:00:00Z":360,"2020-03-06T00:00:00Z":420,"2020-03-07T00:00:00Z":461,"2020-03-08T00:00:00Z":502,"2020-03-09T00:00:00Z":511,"2020-03-10T00:00:00Z":581,"2020-03-11T00:00:00Z":639,"2020-03-12T00:00:00Z":639,"2020-03-13T00:00:00Z":701,"2020-03-14T00:00:00Z":773,"2020-03-15T00:00:00Z":839}},"recovered":{"latest":839,"timeline":{"2020-01-22T00:00:00Z":2,"2020-01-23T00:00:00Z":1,"2020-01-24T00:00:00Z":2,"2020-01-25T00:00:00Z":2,"2020-01-26T00:00:00Z":4,"2020-01-27T00:00:00Z":4,"2020-01-28T00:00:00Z":7,"2020-01-29T00:00:00Z":7,"2020-01-30T00:00:00Z":11,"2020-01-31T00:00:00Z":15,"2020-02-01T00:00:00Z":20,"2020-02-02T00:00:00Z":20,"2020-02-03T00:00:00Z":20,"2020-02-04T00:00:00Z":22,"2020-02-05T00:00:00Z":22,"2020-02-06T00:00:00Z":45,"2020-02-07T00:00:00Z":25,"2020-02-08T00:00:00Z":25,"2020-02-09T00:00:00Z":26,"2020-02-10T00:00:00Z":26,"2020-02-11T00:00:00Z":26,"2020-02-12T00:00:00Z":28,"2020-02-13T00:00:00Z":28,"2020-02-14T00:00:00Z":29,"2020-02-15T00:00:00Z":43,"2020-02-16T00:00:00Z":59,"2020-02-17T00:00:00Z":66,"2020-02-18T00:00:00Z":74,"2020-02-19T00:00:00Z":84,"2020-02-20T00:00:00Z":94,"2020-02-21T00:00:00Z":105,"2020-02-22T00:00:00Z":122,"2020-02-23T00:00:00Z":147,"2020-02-24T00:00:00Z":159,"2020-02-25T00:00:00Z":170,"2020-02-26T00:00:00Z":189,"2020-02-27T00:00:00Z":214,"2020-02-28T00:00:00Z":228,"2020-02-29T00:00:00Z":241,"2020-03-01T00:00:00Z":256,"2020-03-02T00:00:00Z":274,"2020-03-03T00:00:00Z":293,"2020-03-04T00:00:00Z":331,"2020-03-05T00:00:00Z":360,"2020-03-06T00:00:00Z":420,"2020-03-07T00:00:00Z":461,"2020-03-08T00:00:00Z":502,"2020-03-09T00:00:00Z":511,"2020-03-10T00:00:00Z":581,"2020-03-11T00:00:00Z":639,"2020-03-12T00:00:00Z":639,"2020-03-13T00:00:00Z":701,"2020-03-14T00:00:00Z":773,"2020-03-15T00:00:00Z":839}}}}} diff --git a/tests/test_coordinates.py b/tests/test_coordinates.py new file mode 100644 index 00000000..24660790 --- /dev/null +++ b/tests/test_coordinates.py @@ -0,0 +1,19 @@ +from unittest import mock +import pytest + +from app import coordinates + +@pytest.mark.parametrize("latitude, longitude", + [("1", "2"), + (100, "2"), + (-3, 0), + (-10, -10000000)]) +def test_coordinates_class(latitude, longitude): + coord_obj = coordinates.Coordinates(latitude=latitude, + longitude=longitude) + + #validate serialize + check_obj = {'latitude' : latitude, + 'longitude': longitude} + + assert coord_obj.serialize() == check_obj diff --git a/tests/test_data.py b/tests/test_data.py deleted file mode 100644 index 392a07af..00000000 --- a/tests/test_data.py +++ /dev/null @@ -1,71 +0,0 @@ -from unittest import mock -import pytest - -from app import data -from app.utils import date - -""" -Todo: - * More separation of test case `test_data_parsing` -""" - -def mocked_requests_get(*args, **kwargs): - class TestResponse: - def __init__(self, state): - self.text = self.read_file(state) - - def read_file(self, state): - """ - Mock HTTP GET-method and return text from file - """ - filepath = "tests/example_data/time_series_19-covid-{}.csv".format(state) - print("Try to read {}".format(filepath)) - with open(filepath, "r") as file: - return file.read() - - filename = args[0].split("/")[-1] - #clean up for token (e.g. Deaths) - filename = filename.split("-")[-1].replace(".csv", "") - - return TestResponse(filename) - -@pytest.mark.parametrize("state, datetime_str", - [("recovered", "2020-03-17T10:02:01.285418"), - ("deaths", "2020-03-17T10:23:22.505550"), - ("confirmed", "2020-03-17T10:02:01.285418")]) -@mock.patch('app.data.requests.get', side_effect=mocked_requests_get) -@mock.patch('app.data.datetime') -def test_data_parsing(mock_datetime, mock_get, state, datetime_str): - """`data.get_data` sets current datentime via `utcnow()` - Control datetime for testing - Mocked datetime based on `last_updated` of expected_output/data_{state}.json - #datetime value need to be equal due to caching - """ - mock_datetime.utcnow.return_value.isoformat.return_value = datetime_str - output = data.get_data(state) - - #simple schema validation - assert output["source"] == "https://github.com/ExpDev07/coronavirus-tracker-api" - assert isinstance(output["latest"], int) - #check for valid datestring - assert date.is_date(output["last_updated"]) is True - #ensure date formating - assert output["last_updated"] == datetime_str + "Z" - #validate location schema - location_entry = output["locations"][0] - - assert isinstance(location_entry["country"], str) - assert isinstance(location_entry["country_code"], str) - assert len(location_entry["country_code"]) == 2 - assert isinstance(location_entry["province"], str) - assert isinstance(location_entry["latest"], int) - - #validate coordinates in location - coordinates = location_entry["coordinates"] - assert isinstance(coordinates["lat"], str) - assert isinstance(coordinates["long"], str) - - #validate history in location - history = location_entry["history"] - assert date.is_date(list(history.keys())[0]) is True - assert isinstance(list(history.values())[0], int) diff --git a/tests/test_jhu.py b/tests/test_jhu.py new file mode 100644 index 00000000..dcaf5cfa --- /dev/null +++ b/tests/test_jhu.py @@ -0,0 +1,145 @@ +from unittest import mock +import datetime +import pytest + +import app +from app.utils import date +from app import location +from app.services.location import jhu + +DATETIME_STRING = "2020-03-17T10:23:22.505550" + +def mocked_requests_get(*args, **kwargs): + class FakeRequestsGetResponse: + """ + Returns instance of `FakeRequestsGetResponse` + when calling `app.services.location.jhu.requests.get()` + """ + def __init__(self, url, filename, state): + self.url = url + self.filename = filename + self.state = state + self.text = self.read_file(self.state) + + + def read_file(self, state): + """ + Mock HTTP GET-method and return text from file + """ + filepath = "tests/example_data/time_series_19-covid-{}.csv".format(state) + print("Try to read {}".format(filepath)) + with open(filepath, "r") as file: + return file.read() + + #get url from `request.get` + url = args[0] + #get filename from url + filename = url.split("/")[-1] + #clean up for id token (e.g. Deaths) + state = filename.split("-")[-1].replace(".csv", "").lower().capitalize() + + return FakeRequestsGetResponse(url, filename, state) + +def mocked_strptime_isoformat(*args, **kwargs): + class DateTimeStrpTime: + """ + Returns instance of `DateTimeStrpTime` + when calling `app.services.location.jhu.datetime.trptime(date, '%m/%d/%y').isoformat()` + """ + def __init__(self, date, strformat): + self.date = date + self.strformat = strformat + + def isoformat(self): + return datetime.datetime.strptime(self.date, self.strformat).isoformat() + + date = args[0] + strformat = args[1] + + return DateTimeStrpTime(date, strformat) + +@pytest.mark.parametrize("category, capitalize_category", + [("deaths", "Deaths"), + ("recovered", "Recovered"), + ("confirmed", "Confirmed")]) +@mock.patch('app.services.location.jhu.requests.get', side_effect=mocked_requests_get) +def test_validate_category(mock_request_get, category, capitalize_category): + base_url = 'https://raw.githubusercontent.com/CSSEGISandData/2019-nCoV/\ + master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-%s.csv' + + request = app.services.location.jhu.requests.get(base_url % category) + assert request.state == capitalize_category + +@pytest.mark.parametrize("category, datetime_str, latest_value, country_name, \ + country_code, province, latest_country_value, \ + coordinate_lat, coordinate_long", + [("deaths", DATETIME_STRING, 1940, "Thailand", "TH", "", + 114, "15", "101"), + ("recovered", DATETIME_STRING, 1940, "Thailand", "TH", "", + 114, "15", "101"), + ("confirmed", DATETIME_STRING, 1940, "Thailand", "TH", "", + 114, "15", "101")]) +@mock.patch('app.services.location.jhu.datetime') +@mock.patch('app.services.location.jhu.requests.get', side_effect=mocked_requests_get) +def test_get_category(mock_request_get, mock_datetime, category, datetime_str, + latest_value, country_name, country_code, province, latest_country_value, + coordinate_lat, coordinate_long): + #mock app.services.location.jhu.datetime.utcnow().isoformat() + mock_datetime.utcnow.return_value.isoformat.return_value = datetime_str + output = jhu.get_category(category) + + #simple schema validation + assert output["source"] == "https://github.com/ExpDev07/coronavirus-tracker-api" + + assert isinstance(output["latest"], int) + assert output["latest"] == latest_value #based on example data + + #check for valid datestring + assert date.is_date(output["last_updated"]) is True + #ensure date formating + assert output["last_updated"] == datetime_str + "Z" #based on example data + + #validate location schema + location_entry = output["locations"][0] + + assert isinstance(location_entry["country"], str) + assert location_entry["country"] == country_name #based on example data + + assert isinstance(location_entry["country_code"], str) + assert len(location_entry["country_code"]) == 2 + assert location_entry["country_code"] == country_code #based on example data + + assert isinstance(location_entry["province"], str) + assert location_entry["province"] == province #based on example data + + assert isinstance(location_entry["latest"], int) + assert location_entry["latest"] == latest_country_value #based on example data + + #validate coordinates in location + coordinates = location_entry["coordinates"] + + assert isinstance(coordinates["lat"], str) + assert coordinates["lat"] == coordinate_lat + + assert isinstance(coordinates["long"], str) + assert coordinates["long"] == coordinate_long + + #validate history in location + history = location_entry["history"] + assert date.is_date(list(history.keys())[0]) is True + assert isinstance(list(history.values())[0], int) + +@mock.patch('app.services.location.jhu.datetime') +@mock.patch('app.services.location.jhu.requests.get', side_effect=mocked_requests_get) +def test_get_locations(mock_request_get, mock_datetime): + #mock app.services.location.jhu.datetime.utcnow().isoformat() + mock_datetime.utcnow.return_value.isoformat.return_value = DATETIME_STRING + mock_datetime.strptime.side_effect = mocked_strptime_isoformat + + output = jhu.get_locations() + assert isinstance(output, list) + assert isinstance(output[0], location.Location) + + #`jhu.get_locations()` creates id based on confirmed list + location_confirmed = jhu.get_category("confirmed") + assert len(output) == len(location_confirmed["locations"]) diff --git a/tests/test_location.py b/tests/test_location.py new file mode 100644 index 00000000..3465e43a --- /dev/null +++ b/tests/test_location.py @@ -0,0 +1,44 @@ +from unittest import mock +import pytest + +from app import (location, coordinates, timeline) + +def mocked_timeline(*args, **kwargs): + class TestTimeline: + def __init__(self, latest): + self.latest = latest + + return TestTimeline(args[0]) + +@pytest.mark.parametrize("test_id, country, country_code, province, latitude, longitude, \ + confirmed_latest, deaths_latest, recovered_latest", + [(0, "Thailand", "TH", "", 15, 100, 1000, 1111, 22222), + (1, "Deutschland", "DE", "", 15, 100, 1000, 1111, 22222), + (2, "Cruise Ship", "XX", "", 15, 100, 1000, 1111, 22222)]) +@mock.patch('app.timeline.Timeline', side_effect=mocked_timeline) +def test_location_class(mocked_timeline, test_id, country, country_code, province, latitude, + longitude, confirmed_latest, deaths_latest, recovered_latest): + + # id, country, province, coordinates, confirmed, deaths, recovered + coordinate = coordinates.Coordinates(latitude=latitude, longitude=longitude) + confirmed = timeline.Timeline(confirmed_latest) + deaths = timeline.Timeline(deaths_latest) + recovered = timeline.Timeline(recovered_latest) + + location_obj = location.Location(test_id, country, province, coordinate, + confirmed, deaths, recovered) + + assert location_obj.country_code == country_code + + #validate serialize + check_dict = {'id': test_id, + 'country': country, + 'province': province, + 'country_code': country_code, + 'coordinates': {'latitude': latitude, + 'longitude': longitude}, + 'latest': {'confirmed': confirmed_latest, + 'deaths': deaths_latest, + 'recovered': recovered_latest}} + + assert location_obj.serialize() == check_dict diff --git a/tests/test_routes.py b/tests/test_routes.py index b9d1d257..d2fe3ad7 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,66 +1,111 @@ import unittest from unittest import mock +import json import app +from app import services -from .test_data import mocked_requests_get +from .test_jhu import (mocked_requests_get, mocked_strptime_isoformat, + DATETIME_STRING) - -@mock.patch('app.data.requests.get', side_effect=mocked_requests_get) -@mock.patch('app.data.datetime') -class FlaskRoutesTest(unittest.TestCase): +@mock.patch('app.services.location.jhu.datetime') +@mock.patch('app.services.location.jhu.requests.get', side_effect=mocked_requests_get) +class FlaskRoutesV1Test(unittest.TestCase): """ Need to mock some objects to control testing data locally + Routes are hard to test regarding singleton app. + Store all integration testcases in one class to ensure app context """ #load app context only once app = app.create_app() def setUp(self): - self.client = FlaskRoutesTest.app.test_client() - - def test_app_route_recovered(self, mock_datetime, mock_get): - """ - :param mock_datetime: mock.Mock, Mocking object for module path app.data.datetime - :param mock_get: mock.Mock, Mocking object for module path app.data.requests.get - """ - #mocked datetime based on `last_updated` of expected_output/data_{state}.json - #datetime value need to be equal due to caching - mock_datetime.utcnow.return_value.isoformat.return_value = "2020-03-17T10:02:01.285418" - state = "recovered" - filepath = "tests/expected_output/data_{state}.json".format(state=state) + self.client = FlaskRoutesV1Test.app.test_client() + self.date = DATETIME_STRING + + def read_file_v1(self, state): + filepath = "tests/expected_output/v1_{state}.json".format(state=state) with open(filepath, "r") as file: expected_json_output = file.read() + return expected_json_output - output_data = self.client.get("/{}".format(state)).data.decode() + def test_v1_confirmed(self, mock_request_get, mock_datetime): + mock_datetime.utcnow.return_value.isoformat.return_value = self.date + mock_datetime.strptime.side_effect = mocked_strptime_isoformat + state = "confirmed" + expected_json_output = self.read_file_v1(state=state) + return_data = self.client.get("/{}".format(state)).data.decode() - assert output_data == expected_json_output + assert return_data == expected_json_output - def test_app_route_deaths(self, mock_datetime, mock_get): - #mocked datetime based on `last_updated` of expected_output/data_{state}.json - #datetime value need to be equal due to caching - mock_datetime.utcnow.return_value.isoformat.return_value = "2020-03-17T10:23:22.505550" + def test_v1_deaths(self, mock_request_get, mock_datetime): + mock_datetime.utcnow.return_value.isoformat.return_value = self.date + mock_datetime.strptime.side_effect = mocked_strptime_isoformat state = "deaths" - filepath = "tests/expected_output/data_{state}.json".format(state=state) + expected_json_output = self.read_file_v1(state=state) + return_data = self.client.get("/{}".format(state)).data.decode() + + assert return_data == expected_json_output + + def test_v1_recovered(self, mock_request_get, mock_datetime): + mock_datetime.utcnow.return_value.isoformat.return_value = self.date + mock_datetime.strptime.side_effect = mocked_strptime_isoformat + state = "recovered" + expected_json_output = self.read_file_v1(state=state) + return_data = self.client.get("/{}".format(state)).data.decode() + + assert return_data == expected_json_output + + def test_v1_all(self, mock_request_get, mock_datetime): + mock_datetime.utcnow.return_value.isoformat.return_value = self.date + mock_datetime.strptime.side_effect = mocked_strptime_isoformat + state = "all" + expected_json_output = self.read_file_v1(state=state) + return_data = self.client.get("/{}".format(state)).data.decode() + #print(return_data) + assert return_data == expected_json_output + + def test_v2_latest(self, mock_request_get, mock_datetime): + mock_datetime.utcnow.return_value.isoformat.return_value = DATETIME_STRING + mock_datetime.strptime.side_effect = mocked_strptime_isoformat + state = "latest" + return_data = self.client.get("/v2/{}".format(state)).data.decode() + return_data = json.loads(return_data) + + check_dict = {'latest': {'confirmed': 1940, + 'deaths': 1940, + 'recovered': 1940}} + + assert return_data == check_dict + + def test_v2_locations(self, mock_request_get, mock_datetime): + mock_datetime.utcnow.return_value.isoformat.return_value = DATETIME_STRING + mock_datetime.strptime.side_effect = mocked_strptime_isoformat + state = "locations" + return_data = self.client.get("/v2/{}".format(state)).data.decode() + + filepath = "tests/expected_output/v2_{state}.json".format(state=state) with open(filepath, "r") as file: expected_json_output = file.read() - output_data = self.client.get("/{}".format(state)).data.decode() + assert return_data == expected_json_output - assert output_data == expected_json_output + def test_v2_locations_id(self, mock_request_get, mock_datetime): + mock_datetime.utcnow.return_value.isoformat.return_value = DATETIME_STRING + mock_datetime.strptime.side_effect = mocked_strptime_isoformat - def test_app_route_confirmed(self, mock_datetime, mock_get): - #mocked datetime based on `last_updated` of expected_output/data_{state}.json - #datetime value need to be equal due to caching - mock_datetime.utcnow.return_value.isoformat.return_value = "2020-03-17T10:02:01.285418" - state = "confirmed" - filepath = "tests/expected_output/data_{state}.json".format(state=state) + state = "locations" + test_id = 1 + return_data = self.client.get("/v2/{}/{}".format(state, test_id)) \ + .data.decode() + + filepath = "tests/expected_output/v2_{state}_id_{test_id}.json".format(state=state, + test_id=test_id) with open(filepath, "r") as file: expected_json_output = file.read() - output_data = self.client.get("/{}".format(state)).data.decode() - - assert output_data == expected_json_output + assert return_data == expected_json_output def tearDown(self): pass diff --git a/tests/test_timeline.py b/tests/test_timeline.py new file mode 100644 index 00000000..ef1c45ae --- /dev/null +++ b/tests/test_timeline.py @@ -0,0 +1,30 @@ +from unittest import mock +from collections import OrderedDict +import pytest + +from app import timeline + +def test_timeline_class(): + #unordered series + timeseries = {'1/24/20': 5, + '1/22/20': 2, + '1/25/20': 7, + '1/23/20': 3} + + history_data = timeline.Timeline(history=timeseries) + + #validate last value + assert history_data.latest == 7 + + #validate order + assert list(dict(history_data.timeline).keys()) \ + == ['1/22/20', '1/23/20', '1/24/20', '1/25/20'] + + #validate serialize + check_serialize = {'latest': 7, + 'timeline': OrderedDict([('1/22/20', 2), + ('1/23/20', 3), + ('1/24/20', 5), + ('1/25/20', 7)])} + + assert dict(history_data.serialize()) == check_serialize From 81a603629f0e81542f5af7b4e42bb5ab975b5e35 Mon Sep 17 00:00:00 2001 From: gribok <40306040+gribok@users.noreply.github.com> Date: Wed, 18 Mar 2020 22:03:13 +0000 Subject: [PATCH 4/4] fix name of class of FlaskRoutesTest for v1 and v2 testing --- tests/test_routes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_routes.py b/tests/test_routes.py index d2fe3ad7..33429f10 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -10,7 +10,7 @@ @mock.patch('app.services.location.jhu.datetime') @mock.patch('app.services.location.jhu.requests.get', side_effect=mocked_requests_get) -class FlaskRoutesV1Test(unittest.TestCase): +class FlaskRoutesTest(unittest.TestCase): """ Need to mock some objects to control testing data locally Routes are hard to test regarding singleton app. @@ -21,7 +21,7 @@ class FlaskRoutesV1Test(unittest.TestCase): app = app.create_app() def setUp(self): - self.client = FlaskRoutesV1Test.app.test_client() + self.client = FlaskRoutesTest.app.test_client() self.date = DATETIME_STRING def read_file_v1(self, state):