Skip to content
This repository has been archived by the owner on Oct 1, 2018. It is now read-only.

Commit

Permalink
Merge pull request #332 from LinusU/named-endpoints
Browse files Browse the repository at this point in the history
[WIP] Named endpoints
  • Loading branch information
pksunkara committed Jun 5, 2015
2 parents d2e57f8 + 967a672 commit 237091c
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 13 deletions.
47 changes: 34 additions & 13 deletions src/ResourceParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ namespace snowcrash {
/** Named resource matching regex */
const char* const NamedResourceHeaderRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "[[:blank:]]+\\[" URI_TEMPLATE "]$";

/** Named endpoint matching regex */
const char* const NamedEndpointHeaderRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "[[:blank:]]+\\[" HTTP_REQUEST_METHOD "[[:blank:]]+" URI_TEMPLATE "]$";

/** Internal type alias for Collection iterator of Resource */
typedef Collection<Resource>::const_iterator ResourceIterator;

Expand All @@ -49,21 +52,15 @@ namespace snowcrash {

// Make this section an action
if (!captureGroups[2].empty()) {
return processNestedAction(node, node->parent().children(), pd, layout, out);
}
} else if (RegexCapture(node->text, NamedEndpointHeaderRegex, captureGroups, 5)) {

IntermediateParseResult<Action> action(out.report);

MarkdownNodeIterator cur = ActionParser::parse(node, node->parent().children(), pd, action);

out.node.actions.push_back(action.node);
layout = RedirectSectionLayout;

if (pd.exportSourceMap()) {
out.sourceMap.actions.collection.push_back(action.sourceMap);
out.sourceMap.uriTemplate.sourceMap = node->sourceMap;
}
out.node.name = captureGroups[1];
TrimString(out.node.name);
out.node.uriTemplate = captureGroups[3];

return cur;
}
return processNestedAction(node, node->parent().children(), pd, layout, out);
} else {
matchNamedResourceHeader(node, out.node);
}
Expand Down Expand Up @@ -207,6 +204,7 @@ namespace snowcrash {
TrimString(subject);

if (RegexMatch(subject, NamedResourceHeaderRegex) ||
RegexMatch(subject, NamedEndpointHeaderRegex) ||
RegexMatch(subject, ResourceHeaderRegex)) {
return ResourceSectionType;
}
Expand Down Expand Up @@ -336,6 +334,29 @@ namespace snowcrash {
}
}

/**
* \brief Parse the current node as an action
*/
static MarkdownNodeIterator processNestedAction(const MarkdownNodeIterator& node,
const MarkdownNodes& siblings,
SectionParserData& pd,
SectionLayout& layout,
const ParseResultRef<Resource>& out) {

IntermediateParseResult<Action> action(out.report);
MarkdownNodeIterator cur = ActionParser::parse(node, siblings, pd, action);

out.node.actions.push_back(action.node);
layout = RedirectSectionLayout;

if (pd.exportSourceMap()) {
out.sourceMap.actions.collection.push_back(action.sourceMap);
out.sourceMap.uriTemplate.sourceMap = node->sourceMap;
}

return cur;
}

/** Process Action section */
static MarkdownNodeIterator processAction(const MarkdownNodeIterator& node,
const MarkdownNodes& siblings,
Expand Down
85 changes: 85 additions & 0 deletions test/test-ActionParser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// Copyright (c) 2013 Apiary Inc. All rights reserved.
//

#include "snowcrash.h"
#include "snowcrashtest.h"
#include "ActionParser.h"

Expand Down Expand Up @@ -520,3 +521,87 @@ TEST_CASE("Warn when request is not followed by a response", "[action]")
// REQUIRE(action.node.examples[1].requests[0].attributes.source.typeDefinition.typeSpecification.name.base == mson::StringTypeName);
// REQUIRE(action.node.examples[1].responses.size() == 1);
//}

TEST_CASE("Named Endpoint", "[named_endpoint]")
{
const mdp::ByteBuffer source = \
"# Group Test Group\n\n"\
"## My Named Endpoint [GET /test/endpoint]\n\n"\
"Endpoint Description\n\n"\
"+ Response 200 (text/plain)\n\n"\
" OK.";

ParseResult<Blueprint> blueprint;
snowcrash::parse(source, 0, blueprint);

REQUIRE(blueprint.report.error.code == Error::OK);
REQUIRE(blueprint.report.warnings.empty());

REQUIRE(blueprint.node.content.elements().size() == 1);
REQUIRE(blueprint.node.content.elements().at(0).element == Element::CategoryElement);
REQUIRE(blueprint.node.content.elements().at(0).content.elements().size() == 1);
REQUIRE(blueprint.node.content.elements().at(0).content.elements().at(0).element == Element::ResourceElement);

Resource resource = blueprint.node.content.elements().at(0).content.elements().at(0).content.resource;
REQUIRE(resource.name == "My Named Endpoint");
REQUIRE(resource.uriTemplate == "/test/endpoint");
REQUIRE(resource.actions.size() == 1);

Action action = resource.actions.at(0);
REQUIRE(action.method == "GET");
}

TEST_CASE("Named Endpoints Edge Cases", "[named_endpoint]")
{
const mdp::ByteBuffer source = \
"# Endpoint 1 [GET /e1]\n\n"\
"+ Response 204\n\n"\
"# Endpoint 2 [GET /e1]\n\n"\
"+ Response 204\n\n"\
"# Endpoint 3 [POST /e1]\n\n"\
"+ Response 204\n";

ParseResult<Blueprint> blueprint;
snowcrash::parse(source, 0, blueprint);

REQUIRE(blueprint.report.error.code == Error::OK);
REQUIRE(blueprint.report.warnings.size() == 2);

REQUIRE(blueprint.report.warnings.at(0).code == DuplicateWarning);
REQUIRE(blueprint.report.warnings.at(1).code == DuplicateWarning);

REQUIRE(blueprint.node.content.elements().size() == 1);
REQUIRE(blueprint.node.content.elements().at(0).element == Element::CategoryElement);
REQUIRE(blueprint.node.content.elements().at(0).content.elements().size() == 3);
REQUIRE(blueprint.node.content.elements().at(0).content.elements().at(0).element == Element::ResourceElement);

{
Resource resource = blueprint.node.content.elements().at(0).content.elements().at(0).content.resource;
REQUIRE(resource.name == "Endpoint 1");
REQUIRE(resource.uriTemplate == "/e1");
REQUIRE(resource.actions.size() == 1);

Action action = resource.actions.at(0);
REQUIRE(action.method == "GET");
}

{
Resource resource = blueprint.node.content.elements().at(0).content.elements().at(1).content.resource;
REQUIRE(resource.name == "Endpoint 2");
REQUIRE(resource.uriTemplate == "/e1");
REQUIRE(resource.actions.size() == 1);

Action action = resource.actions.at(0);
REQUIRE(action.method == "GET");
}

{
Resource resource = blueprint.node.content.elements().at(0).content.elements().at(2).content.resource;
REQUIRE(resource.name == "Endpoint 3");
REQUIRE(resource.uriTemplate == "/e1");
REQUIRE(resource.actions.size() == 1);

Action action = resource.actions.at(0);
REQUIRE(action.method == "POST");
}
}

0 comments on commit 237091c

Please sign in to comment.