2012-10-16 19:56:54 +02:00
|
|
|
/*
|
2012-11-03 19:52:49 +01:00
|
|
|
Parson ( http://kgabis.github.com/parson/ )
|
2012-10-16 19:56:54 +02:00
|
|
|
Copyright (c) 2012 Krzysztof Gabis
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
*/
|
2012-11-03 08:19:28 -04:00
|
|
|
|
|
|
|
#include "parson.h"
|
|
|
|
|
2012-10-16 19:56:54 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define TEST(A) printf("%-72s-",#A); \
|
|
|
|
if(A){puts(" OK");tests_passed++;} \
|
|
|
|
else{puts(" FAIL");tests_failed++;}
|
2012-10-18 15:25:11 +02:00
|
|
|
#define STREQ(A, B) (A && B ? strcmp(A, B) == 0 : 0)
|
2012-10-16 19:56:54 +02:00
|
|
|
|
2012-10-19 16:24:24 +02:00
|
|
|
void test_suite_1(void);
|
|
|
|
void test_suite_2(void);
|
|
|
|
void test_suite_3(void);
|
2012-10-16 19:56:54 +02:00
|
|
|
|
2012-10-22 19:20:02 +02:00
|
|
|
void print_commits_info(const char *username, const char *repo);
|
2012-10-16 19:56:54 +02:00
|
|
|
|
|
|
|
static int tests_passed;
|
|
|
|
static int tests_failed;
|
|
|
|
|
2012-12-02 18:33:00 +01:00
|
|
|
int main() {
|
2012-10-22 19:20:02 +02:00
|
|
|
/* Example function from readme file: */
|
|
|
|
/* print_commits_info("torvalds", "linux"); */
|
2012-10-16 19:56:54 +02:00
|
|
|
test_suite_1();
|
|
|
|
test_suite_2();
|
|
|
|
test_suite_3();
|
|
|
|
printf("Tests failed: %d\n", tests_failed);
|
|
|
|
printf("Tests passed: %d\n", tests_passed);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 3 test files from json.org */
|
2012-10-19 16:24:24 +02:00
|
|
|
void test_suite_1(void) {
|
|
|
|
JSON_Value *val;
|
|
|
|
TEST((val = json_parse_file("tests/test_1_1.txt")) != NULL);
|
|
|
|
if (val) { json_value_free(val); }
|
|
|
|
TEST((val = json_parse_file("tests/test_1_2.txt")) != NULL);
|
|
|
|
if (val) { json_value_free(val); }
|
|
|
|
TEST((val = json_parse_file("tests/test_1_3.txt")) != NULL);
|
|
|
|
if (val) { json_value_free(val); }
|
2012-10-16 19:56:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Testing correctness of parsed values */
|
2012-10-19 16:24:24 +02:00
|
|
|
void test_suite_2(void) {
|
2012-10-16 19:56:54 +02:00
|
|
|
JSON_Value *root_value;
|
|
|
|
JSON_Object *object;
|
|
|
|
JSON_Array *array;
|
2012-12-02 18:33:00 +01:00
|
|
|
size_t i;
|
2012-10-16 19:56:54 +02:00
|
|
|
const char *filename = "tests/test_2.txt";
|
2012-11-03 19:52:49 +01:00
|
|
|
printf("Testing %s:\n", filename);
|
2012-10-16 19:56:54 +02:00
|
|
|
root_value = json_parse_file(filename);
|
2012-10-22 19:20:02 +02:00
|
|
|
TEST(root_value);
|
2012-11-03 19:52:49 +01:00
|
|
|
TEST(json_value_get_type(root_value) == JSONObject);
|
|
|
|
object = json_value_get_object(root_value);
|
2012-10-16 19:56:54 +02:00
|
|
|
TEST(STREQ(json_object_get_string(object, "string"), "lorem ipsum"));
|
|
|
|
TEST(STREQ(json_object_get_string(object, "utf string"), "lorem ipsum"));
|
2013-02-07 17:23:57 +09:00
|
|
|
TEST(STREQ(json_object_get_string(object, "utf-8 string"), "あいうえお"));
|
2012-10-16 19:56:54 +02:00
|
|
|
TEST(json_object_get_number(object, "positive one") == 1.0);
|
|
|
|
TEST(json_object_get_number(object, "negative one") == -1.0);
|
|
|
|
TEST(json_object_get_number(object, "hard to parse number") == -0.000314);
|
2012-10-18 15:25:11 +02:00
|
|
|
TEST(json_object_get_boolean(object, "boolean true") == 1);
|
|
|
|
TEST(json_object_get_boolean(object, "boolean false") == 0);
|
2012-10-16 19:56:54 +02:00
|
|
|
TEST(json_value_get_type(json_object_get_value(object, "null")) == JSONNull);
|
|
|
|
|
|
|
|
array = json_object_get_array(object, "string array");
|
|
|
|
if (array != NULL && json_array_get_count(array) > 1) {
|
|
|
|
TEST(STREQ(json_array_get_string(array, 0), "lorem"));
|
|
|
|
TEST(STREQ(json_array_get_string(array, 1), "ipsum"));
|
|
|
|
} else {
|
|
|
|
tests_failed++;
|
|
|
|
}
|
|
|
|
|
|
|
|
array = json_object_get_array(object, "x^2 array");
|
|
|
|
if (array != NULL) {
|
|
|
|
for (i = 0; i < json_array_get_count(array); i++) {
|
|
|
|
TEST(json_array_get_number(array, i) == (i * i));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tests_failed++;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(json_object_get_array(object, "non existent array") == NULL);
|
|
|
|
TEST(STREQ(json_object_dotget_string(object, "object.nested string"), "str"));
|
2012-10-22 19:20:02 +02:00
|
|
|
TEST(json_object_dotget_boolean(object, "object.nested true") == 1);
|
|
|
|
TEST(json_object_dotget_boolean(object, "object.nested false") == 0);
|
2012-10-16 19:56:54 +02:00
|
|
|
TEST(json_object_dotget_value(object, "object.nested null") != NULL);
|
|
|
|
TEST(json_object_dotget_number(object, "object.nested number") == 123);
|
|
|
|
|
|
|
|
TEST(json_object_dotget_value(object, "should.be.null") == NULL);
|
|
|
|
TEST(json_object_dotget_value(object, "should.be.null.") == NULL);
|
|
|
|
TEST(json_object_dotget_value(object, ".") == NULL);
|
|
|
|
TEST(json_object_dotget_value(object, "") == NULL);
|
|
|
|
|
|
|
|
array = json_object_dotget_array(object, "object.nested array");
|
|
|
|
if (array != NULL && json_array_get_count(array) > 1) {
|
|
|
|
TEST(STREQ(json_array_get_string(array, 0), "lorem"));
|
|
|
|
TEST(STREQ(json_array_get_string(array, 1), "ipsum"));
|
|
|
|
} else {
|
|
|
|
tests_failed++;
|
|
|
|
}
|
2012-12-02 18:33:00 +01:00
|
|
|
TEST(json_object_dotget_boolean(object, "nested true"));
|
2012-10-16 19:56:54 +02:00
|
|
|
json_value_free(root_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Testing values, on which parsing should fail */
|
2012-10-19 16:24:24 +02:00
|
|
|
void test_suite_3(void) {
|
2012-10-22 19:20:02 +02:00
|
|
|
char nested_20x[] = "[[[[[[[[[[[[[[[[[[[[\"hi\"]]]]]]]]]]]]]]]]]]]]";
|
Code refractoring.
Details:
- Increased STARTING_CAPACITY from 10 to 15.
- Added 2 macros: skip_char and skip_whitespaces.
- Added json_object_nget_value function, which removes neccessity to allocate new string when using dotget functions.
- Removed parson_strdup function, it was called only once and could be easilly replaced with appropriate call to parson_strndup.
- Renamed skip_string to skip_quotes, which is a more appropriate name, and made it work on a passed pointer to a string, which is much like skip_char and skip_whitespaces.
- Removed copy_and_remove_whitespaces, it was unncessary, and could be easily replaced with skip_whitepsaces macro.
- Merged parse_escaped_characters and get_string to get_processed_string, which makes more sense.
- Changed is_decimal implementation, to avoid unncessary string duplicating.
- Removed string copying in parse_number value and json_parse_string, since it was unncessary.
2012-11-04 17:45:52 +01:00
|
|
|
puts("Testing invalid strings:");
|
2012-10-16 19:56:54 +02:00
|
|
|
TEST(json_parse_string(NULL) == NULL);
|
|
|
|
TEST(json_parse_string("") == NULL); /* empty string */
|
|
|
|
TEST(json_parse_string("[\"lorem\",]") == NULL);
|
|
|
|
TEST(json_parse_string("[,]") == NULL);
|
|
|
|
TEST(json_parse_string("[,") == NULL);
|
|
|
|
TEST(json_parse_string("[") == NULL);
|
|
|
|
TEST(json_parse_string("]") == NULL);
|
|
|
|
TEST(json_parse_string("{\"a\":0,\"a\":0}") == NULL); /* duplicate keys */
|
|
|
|
TEST(json_parse_string("{:,}") == NULL);
|
|
|
|
TEST(json_parse_string("{,}") == NULL);
|
|
|
|
TEST(json_parse_string("{,") == NULL);
|
|
|
|
TEST(json_parse_string("{:") == NULL);
|
|
|
|
TEST(json_parse_string("{") == NULL);
|
|
|
|
TEST(json_parse_string("}") == NULL);
|
|
|
|
TEST(json_parse_string("x") == NULL);
|
|
|
|
TEST(json_parse_string("\"string\"") == NULL);
|
|
|
|
TEST(json_parse_string("{:\"no name\"}") == NULL);
|
|
|
|
TEST(json_parse_string("[,\"no first value\"]") == NULL);
|
|
|
|
TEST(json_parse_string("[\"\\u00zz\"]") == NULL); /* invalid utf value */
|
2012-10-24 10:41:05 +02:00
|
|
|
TEST(json_parse_string("[\"\\u00\"]") == NULL); /* invalid utf value */
|
|
|
|
TEST(json_parse_string("[\"\\u\"]") == NULL); /* invalid utf value */
|
2012-10-16 19:56:54 +02:00
|
|
|
TEST(json_parse_string("[\"\\\"]") == NULL); /* control character */
|
|
|
|
TEST(json_parse_string("[\"\"\"]") == NULL); /* control character */
|
|
|
|
TEST(json_parse_string("[\"\0\"]") == NULL); /* control character */
|
|
|
|
TEST(json_parse_string("[\"\a\"]") == NULL); /* control character */
|
|
|
|
TEST(json_parse_string("[\"\b\"]") == NULL); /* control character */
|
|
|
|
TEST(json_parse_string("[\"\t\"]") == NULL); /* control character */
|
|
|
|
TEST(json_parse_string("[\"\n\"]") == NULL); /* control character */
|
|
|
|
TEST(json_parse_string("[\"\f\"]") == NULL); /* control character */
|
|
|
|
TEST(json_parse_string("[\"\r\"]") == NULL); /* control character */
|
2012-10-19 16:24:24 +02:00
|
|
|
TEST(json_parse_string(nested_20x) == NULL); /* too deep */
|
2012-10-24 10:41:05 +02:00
|
|
|
TEST(json_parse_string("[0x2]") == NULL); /* hex */
|
|
|
|
TEST(json_parse_string("[0X2]") == NULL); /* HEX */
|
|
|
|
TEST(json_parse_string("[07]") == NULL); /* octals */
|
|
|
|
TEST(json_parse_string("[0070]") == NULL);
|
|
|
|
TEST(json_parse_string("[07.0]") == NULL);
|
|
|
|
TEST(json_parse_string("[-07]") == NULL);
|
|
|
|
TEST(json_parse_string("[-007]") == NULL);
|
|
|
|
TEST(json_parse_string("[-07.0]") == NULL);
|
2012-10-16 19:56:54 +02:00
|
|
|
}
|
|
|
|
|
2012-10-22 19:20:02 +02:00
|
|
|
void print_commits_info(const char *username, const char *repo) {
|
2012-10-16 19:56:54 +02:00
|
|
|
JSON_Value *root_value;
|
|
|
|
JSON_Array *commits;
|
|
|
|
JSON_Object *commit;
|
2012-12-02 18:33:00 +01:00
|
|
|
size_t i;
|
2012-10-16 19:56:54 +02:00
|
|
|
|
|
|
|
char curl_command[512];
|
|
|
|
char cleanup_command[256];
|
2012-10-18 17:18:44 +02:00
|
|
|
char output_filename[] = "commits.json";
|
2012-10-16 19:56:54 +02:00
|
|
|
|
|
|
|
/* it ain't pretty, but it's not a libcurl tutorial */
|
2012-11-24 20:59:16 +01:00
|
|
|
sprintf(curl_command,
|
|
|
|
"curl -s \"https://api.github.com/repos/%s/%s/commits\" > %s",
|
|
|
|
username, repo, output_filename);
|
2012-10-16 19:56:54 +02:00
|
|
|
sprintf(cleanup_command, "rm -f %s", output_filename);
|
|
|
|
system(curl_command);
|
|
|
|
|
|
|
|
/* parsing json and validating output */
|
|
|
|
root_value = json_parse_file(output_filename);
|
2012-11-24 20:59:16 +01:00
|
|
|
if (json_value_get_type(root_value) != JSONArray) {
|
2012-10-16 19:56:54 +02:00
|
|
|
system(cleanup_command);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* getting array from root value and printing commit info */
|
|
|
|
commits = json_value_get_array(root_value);
|
|
|
|
printf("%-10.10s %-10.10s %s\n", "Date", "SHA", "Author");
|
|
|
|
for (i = 0; i < json_array_get_count(commits); i++) {
|
|
|
|
commit = json_array_get_object(commits, i);
|
|
|
|
printf("%.10s %.10s %s\n",
|
|
|
|
json_object_dotget_string(commit, "commit.author.date"),
|
|
|
|
json_object_get_string(commit, "sha"),
|
|
|
|
json_object_dotget_string(commit, "commit.author.name"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cleanup code */
|
|
|
|
json_value_free(root_value);
|
|
|
|
system(cleanup_command);
|
|
|
|
}
|