blob: adead69fdca0648bb24a67367e0a1394ad48a9c2 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libipp/ipp.h"
#include <cstdint>
#include <string>
#include <vector>
#include <gtest/gtest.h>
// This file contains unit test based on examples from [rfc8010].
namespace ipp {
static bool operator==(const ipp::Resolution& a, const ipp::Resolution& b) {
return (a.xres == b.xres && a.yres == b.yres && a.units == b.units);
}
static bool operator==(const ipp::RangeOfInteger& a,
const ipp::RangeOfInteger& b) {
return (a.min_value == b.min_value && a.max_value == b.max_value);
}
static bool operator==(const ipp::DateTime& a, const ipp::DateTime& b) {
return (a.UTC_direction == b.UTC_direction && a.UTC_hours == b.UTC_hours &&
a.UTC_minutes == b.UTC_minutes && a.day == b.day &&
a.hour == b.hour && a.deci_seconds == b.deci_seconds &&
a.minutes == b.minutes && a.month == b.month &&
a.seconds == b.seconds && a.year == b.year);
}
} // namespace ipp
namespace {
uint32_t TwosComplementEncoding(int value) {
if (value >= 0)
return value;
uint32_t binary = -static_cast<int64_t>(value);
binary = ~binary;
++binary;
return binary;
}
// Helps build binary representation of frames from examples copied from
// [rfc8010].
struct BinaryContent {
// frame content
std::vector<uint8_t> data;
// add field with ASCII string
void s(std::string s) {
for (auto c : s) {
data.push_back(static_cast<uint8_t>(c));
}
}
// add 1 byte
void u1(int v) {
const uint32_t b = TwosComplementEncoding(v);
data.push_back(b & 0xffu);
}
// add 2 bytes
void u2(int v) {
const uint32_t b = TwosComplementEncoding(v);
data.push_back((b >> 8) & 0xffu);
data.push_back(b & 0xffu);
}
// add 4 bytes
void u4(int v) {
const uint32_t b = TwosComplementEncoding(v);
data.push_back((b >> 24) & 0xffu);
data.push_back((b >> 16) & 0xffu);
data.push_back((b >> 8) & 0xffu);
data.push_back(b & 0xffu);
}
};
// function comparing if two collections have the same content
void CompareCollections(ipp::Collection* c1, ipp::Collection* c2) {
std::vector<ipp::Attribute*> a1 = c1->GetAllAttributes();
std::vector<ipp::Attribute*> a2 = c2->GetAllAttributes();
ASSERT_EQ(a1.size(), a2.size());
for (size_t i = 0; i < a1.size(); ++i) {
EXPECT_EQ(a1[i]->GetName(), a2[i]->GetName());
EXPECT_EQ(a1[i]->GetType(), a2[i]->GetType());
EXPECT_EQ(a1[i]->IsASet(), a2[i]->IsASet());
EXPECT_EQ(a1[i]->GetState(), a2[i]->GetState());
ASSERT_EQ(a1[i]->GetSize(), a2[i]->GetSize());
for (size_t j = 0; j < a1[i]->GetSize(); ++j) {
std::string s1, s2;
ipp::DateTime d1, d2;
ipp::Resolution r1, r2;
ipp::RangeOfInteger i1, i2;
ipp::StringWithLanguage l1, l2;
switch (a1[i]->GetType()) {
case ipp::AttrType::text:
case ipp::AttrType::name:
a1[i]->GetValue(&l1, j);
a2[i]->GetValue(&l2, j);
EXPECT_EQ(l1.value, l2.value);
EXPECT_EQ(l1.language, l2.language);
break;
case ipp::AttrType::integer:
case ipp::AttrType::boolean:
case ipp::AttrType::enum_:
case ipp::AttrType::octetString:
case ipp::AttrType::keyword:
case ipp::AttrType::uri:
case ipp::AttrType::uriScheme:
case ipp::AttrType::charset:
case ipp::AttrType::naturalLanguage:
case ipp::AttrType::mimeMediaType:
a1[i]->GetValue(&s1, j);
a2[i]->GetValue(&s2, j);
EXPECT_EQ(s1, s2);
break;
case ipp::AttrType::dateTime:
a1[i]->GetValue(&d1, j);
a2[i]->GetValue(&d2, j);
EXPECT_EQ(d1, d2);
break;
case ipp::AttrType::resolution:
a1[i]->GetValue(&r1, j);
a2[i]->GetValue(&r2, j);
EXPECT_EQ(r1, r2);
break;
case ipp::AttrType::rangeOfInteger:
a1[i]->GetValue(&i1, j);
a2[i]->GetValue(&i2, j);
EXPECT_EQ(i1, i2);
break;
case ipp::AttrType::collection:
CompareCollections(a1[i]->GetCollection(j), a2[i]->GetCollection(j));
break;
}
}
}
}
// checks if given frame is a binary representation of given Request
void CheckRequest(const BinaryContent& frame,
ipp::Request* req,
const int32_t request_no = 1) {
// build output frame from Request and compare with the given frame
ipp::Client client(ipp::Version::_1_1, request_no - 1);
client.BuildRequestFrom(req);
EXPECT_TRUE(client.GetErrorLog().empty());
std::vector<uint8_t> bin_data;
ASSERT_TRUE(client.WriteRequestFrameTo(&bin_data));
EXPECT_TRUE(client.GetErrorLog().empty());
EXPECT_EQ(client.GetFrameLength(), bin_data.size());
EXPECT_EQ(bin_data, frame.data);
// parse the given frame and compare obtained object with the given Request
ipp::Server server(ipp::Version::_1_1, request_no);
auto req2 = ipp::Request::NewRequest(req->GetOperationId());
ASSERT_TRUE(server.ReadRequestFrameFrom(bin_data));
EXPECT_TRUE(server.GetErrorLog().empty());
ASSERT_TRUE(server.ParseRequestAndSaveTo(req2.get()));
EXPECT_TRUE(server.GetErrorLog().empty());
// ... compares two request objects
std::vector<ipp::Group*> groups1 = req->GetAllGroups();
std::vector<ipp::Group*> groups2 = req2->GetAllGroups();
ASSERT_EQ(groups1.size(), groups2.size());
for (size_t i = 0; i < groups1.size(); ++i) {
ipp::Group* g1 = groups1[i];
ipp::Group* g2 = groups2[i];
EXPECT_EQ(g1->GetName(), g2->GetName());
ASSERT_EQ(g1->GetSize(), g2->GetSize());
for (size_t j = 0; j < g1->GetSize(); ++j)
CompareCollections(g1->GetCollection(j), g2->GetCollection(j));
}
EXPECT_EQ(req->Data(), req2->Data());
}
// checks if given frame is a binary representation of given Response
void CheckResponse(const BinaryContent& frame,
ipp::Response* res,
const int32_t request_no = 1) {
// build output frame from Response and compare with the given frame
ipp::Server server(ipp::Version::_1_1, request_no);
server.BuildResponseFrom(res);
EXPECT_TRUE(server.GetErrorLog().empty());
std::vector<uint8_t> bin_data;
ASSERT_TRUE(server.WriteResponseFrameTo(&bin_data));
EXPECT_TRUE(server.GetErrorLog().empty());
EXPECT_EQ(server.GetFrameLength(), bin_data.size());
EXPECT_EQ(bin_data, frame.data);
// parse the given frame and compare obtained object with the given Response
ipp::Client client(ipp::Version::_1_1, request_no - 1);
auto res2 = ipp::Response::NewResponse(res->GetOperationId());
ASSERT_TRUE(client.ReadResponseFrameFrom(bin_data));
EXPECT_TRUE(client.GetErrorLog().empty());
ASSERT_TRUE(client.ParseResponseAndSaveTo(res2.get()));
EXPECT_TRUE(client.GetErrorLog().empty());
// ... compares two response objects
EXPECT_EQ(res->StatusCode(), res2->StatusCode());
std::vector<ipp::Group*> groups1 = res->GetAllGroups();
std::vector<ipp::Group*> groups2 = res2->GetAllGroups();
ASSERT_EQ(groups1.size(), groups2.size());
for (size_t i = 0; i < groups1.size(); ++i) {
ipp::Group* g1 = groups1[i];
ipp::Group* g2 = groups2[i];
EXPECT_EQ(g1->GetName(), g2->GetName());
ASSERT_EQ(g1->GetSize(), g2->GetSize());
for (size_t j = 0; j < g1->GetSize(); ++j)
CompareCollections(g1->GetCollection(j), g2->GetCollection(j));
}
EXPECT_EQ(res->Data(), res2->Data());
}
TEST(rfc8010, example1) {
// A.1. Print-Job Request
// The following is an example of a Print-Job request with "job-name",
// "copies", and "sides" specified. The "ipp-attribute-fidelity"
// attribute is set to 'true' so that the print request will fail if the
// "copies" or the "sides" attribute is not supported or their values
// are not supported.
BinaryContent c;
// Octets Symbolic Value Protocol field
c.u2(0x0101u); // 1.1 version-number
c.u2(0x0002u); // Print-Job operation-id
c.u4(0x00000001u); // 1 request-id
c.u1(0x01u); // start operation- operation-
// attributes attributes-tag
c.u1(0x47u); // charset type value-tag
c.u2(0x0012u); // name-length
c.s("attributes-charset"); // attributes-charset name
c.u2(0x0005u); // value-length
c.s("utf-8"); // UTF-8 value
c.u1(0x48u); // natural-language value-tag
// type
c.u2(0x001bu); // name-length
c.s("attributes-natural-language"); // attributes-natural- name
// language
c.u2(0x0005u); // value-length
c.s("en-us"); // en-US value
c.u1(0x45u); // uri type value-tag
c.u2(0x000bu); // name-length
c.s("printer-uri"); // printer-uri name
c.u2(0x002cu); // value-length
c.s("ipp://printer.example.com/ipp/"); // printer pinetree value
c.s("print/pinetree");
c.u1(0x42u); // nameWithoutLanguage value-tag
// type
c.u2(0x0008u); // name-length
c.s("job-name"); // job-name name
c.u2(0x0006u); // value-length
c.s("foobar"); // foobar value
c.u1(0x22u); // boolean type value-tag
c.u2(0x0016u); // name-length
c.s("ipp-attribute-fidelity"); // ipp-attribute- name
// fidelity
c.u2(0x0001u); // value-length
c.u1(0x01u); // true value
c.u1(0x02u); // start job-attributes job-attributes-
// tag
c.u1(0x21u); // integer type value-tag
c.u2(0x0006u); // name-length
c.s("copies"); // copies name
c.u2(0x0004u); // value-length
c.u4(0x00000014u); // 20 value
c.u1(0x44u); // keyword type value-tag
c.u2(0x0005u); // name-length
c.s("sides"); // sides name
c.u2(0x0013u); // value-length
c.s("two-sided-long-edge"); // two-sided-long-edge value
c.u1(0x03u); // end-of-attributes end-of-
// attributes-tag
c.s("%!PDF..."); // <PDF Document> data
ipp::Request_Print_Job r;
r.operation_attributes->printer_uri.Set(
"ipp://printer.example.com/ipp/print/pinetree");
r.operation_attributes->job_name.Set("foobar");
r.operation_attributes->ipp_attribute_fidelity.Set(1);
r.job_attributes->copies.Set(20);
r.job_attributes->sides.Set(ipp::E_sides::two_sided_long_edge);
for (char c : std::string("%!PDF..."))
r.Data().push_back(static_cast<uint8_t>(c));
CheckRequest(c, &r);
}
TEST(rfc8010, example2) {
// A.2. Print-Job Response (Successful)
// Here is an example of a successful Print-Job response to the previous
// Print-Job request. The Printer supported the "copies" and "sides"
// attributes and their supplied values. The status-code returned is
// 'successful-ok'.
BinaryContent c;
// Octets Symbolic Value Protocol field
c.u2(0x0101u); // 1.1 version-number
c.u2(0x0000u); // successful-ok status-code
c.u4(0x00000001u); // 1 request-id
c.u1(0x01u); // start operation- operation-
// attributes attributes-tag
c.u1(0x47u); // charset type value-tag
c.u2(0x0012u); // name-length
c.s("attributes-charset"); // attributes-charset name
c.u2(0x0005u); // value-length
c.s("utf-8"); // UTF-8 value
c.u1(0x48u); // natural-language value-tag
// type
c.u2(0x001bu); // name-length
c.s("attributes-natural-language"); // attributes- name
// natural-language
c.u2(0x0005u); // value-length
c.s("en-us"); // en-US value
c.u1(0x41u); // textWithoutLanguag value-tag
// e type
c.u2(0x000eu); // name-length
c.s("status-message"); // status-message name
c.u2(0x000du); // value-length
c.s("successful-ok"); // successful-ok value
c.u1(0x02u); // start job- job-attributes-
// attributes tag
c.u1(0x21u); // integer value-tag
c.u2(0x0006u); // name-length
c.s("job-id"); // job-id name
c.u2(0x0004u); // value-length
c.u4(147); // 147 value
c.u1(0x45u); // uri type value-tag
c.u2(0x0007u); // name-length
c.s("job-uri"); // job-uri name
c.u2(0x0030u); // value-length
c.s("ipp://printer.example.com/ipp/pr"); // job 147 on value
c.s("int/pinetree/147"); // pinetree
c.u1(0x23u); // enum type value-tag
c.u2(0x0009u); // name-length
c.s("job-state"); // job-state name
c.u2(0x0004u); // value-length
c.u4(0x0003u); // pending value
c.u1(0x03u); // end-of-attributes end-of-
// attributes-tag
ipp::Response_Print_Job r;
r.job_attributes->job_id.Set(147);
r.job_attributes->job_uri.Set(
"ipp://printer.example.com/ipp/print/pinetree/147");
r.job_attributes->job_state.Set(ipp::E_job_state::pending);
CheckResponse(c, &r);
}
TEST(rfc8010, example3) {
// A.3. Print-Job Response (Failure)
// Here is an example of an unsuccessful Print-Job response to the
// previous Print-Job request. It fails because, in this case, the
// Printer does not support the "sides" attribute and because the value
// '20' for the "copies" attribute is not supported. Therefore, no Job
// is created, and neither a "job-id" nor a "job-uri" operation
// attribute is returned. The error code returned is 'client-error-
// attributes-or-values-not-supported' (0x040b).
BinaryContent c;
// Octets Symbolic Value Protocol
// field
c.u2(0x0101u); // 1.1 version-
// number
c.u2(0x040bu); // client-error-attributes-or- status-code
// values-not-supported
c.u4(0x00000001u); // 1 request-id
c.u1(0x01u); // start operation-attributes operation-
// attributes
// tag
c.u1(0x47u); // charset type value-tag
c.u2(0x0012u); // name-length
c.s("attributes-charset"); // attributes-charset name
c.u2(0x0005u); // value-length
c.s("utf-8"); // UTF-8 value
c.u1(0x48u); // natural-language type value-tag
c.u2(0x001bu); // name-length
c.s("attributes-natural-language"); // attributes-natural-language name
c.u2(0x0005u); // value-length
c.s("en-us"); // en-US value
c.u1(0x41u); // textWithoutLanguage type value-tag
c.u2(0x000eu); // name-length
c.s("status-message"); // status-message name
c.u2(0x002fu); // value-length
c.s("client-error-attributes-or-"); // client-error-attributes-or- value
c.s("values-not-supported"); // values-not-supported
c.u1(0x05u); // start unsupported- unsupported-
// attributes attributes
// tag
c.u1(0x21u); // integer type value-tag
c.u2(0x0006u); // name-length
c.s("copies"); // copies name
c.u2(0x0004u); // value-length
c.u4(0x00000014u); // 20 value
c.u1(0x10u); // unsupported (type) value-tag
c.u2(0x0005u); // name-length
c.s("sides"); // sides name
c.u2(0x0000u); // value-length
c.u1(0x03u); // end-of-attributes end-of-
// attributes-
// tag
ipp::Response_Print_Job r;
r.StatusCode() =
ipp::E_status_code::client_error_attributes_or_values_not_supported;
ipp::Attribute* a = r.unsupported_attributes->AddUnknownAttribute(
"copies", true, ipp::AttrType::integer);
a->SetValue(20);
a = r.unsupported_attributes->AddUnknownAttribute("sides", true,
ipp::AttrType::integer);
a->SetState(ipp::AttrState::unsupported);
CheckResponse(c, &r);
}
TEST(rfc8010, example4) {
// A.4. Print-Job Response (Success with Attributes Ignored)
// Here is an example of a successful Print-Job response to a Print-Job
// request like the previous Print-Job request, except that the value of
// "ipp-attribute-fidelity" is 'false'. The print request succeeds,
// even though, in this case, the Printer supports neither the "sides"
// attribute nor the value '20' for the "copies" attribute. Therefore,
// a Job is created and both a "job-id" and a "job-uri" operation
// attribute are returned. The unsupported attributes are also returned
// in an Unsupported Attributes group. The error code returned is
// 'successful-ok-ignored-or-substituted-attributes' (0x0001).
BinaryContent c;
// Octets Symbolic Value Protocol
// field
c.u2(0x0101u); // 1.1 version-number
c.u2(0x0001u); // successful-ok-ignored-or- status-coder.StatusCode() =
// static_cast<uint16_t>(ipp::E_status_code::successful_ok);
// substituted-attributes
c.u4(0x00000001u); // 1 request-id
c.u1(0x01u); // start operation-attributes operation-
// attributes-tag
c.u1(0x47u); // charset type value-tag
c.u2(0x0012u); // name-length
c.s("attributes-charset"); // attributes-charset name
c.u2(0x0005u); // value-length
c.s("utf-8"); // UTF-8 value
c.u1(0x48u); // natural-language type value-tag
c.u2(0x001bu); // name-length
c.s("attributes-natural-"); // attributes-natural-language name
c.s("language");
c.u2(0x0005u); // value-length
c.s("en-us"); // en-US value
c.u1(0x41u); // textWithoutLanguage type value-tag
c.u2(0x000eu); // name-length
c.s("status-message"); // status-message name
c.u2(0x002fu); // value-length
c.s("successful-ok-ignored-or-"); // successful-ok-ignored-or- value
c.s("substituted-attributes"); // substituted-attributes
c.u1(0x05u); // start unsupported- unsupported-
// attributes attributes tag
c.u1(0x21u); // integer type value-tag
c.u2(0x0006u); // name-length
c.s("copies"); // copies name
c.u2(0x0004u); // value-length
c.u4(0x00000014u); // 20 value
c.u1(0x10u); // unsupported (type) value-tag
c.u2(0x0005u); // name-length
c.s("sides"); // sides name
c.u2(0x0000u); // value-length
c.u1(0x02u); // start job-attributes job-
// attributes-tag
c.u1(0x21u); // integer value-tag
c.u2(0x0006u); // name-length
c.s("job-id"); // job-id name
c.u2(0x0004u); // value-length
c.u4(147); // 147 value
c.u1(0x45u); // uri type value-tag
c.u2(0x0007u); // name-length
c.s("job-uri"); // job-uri name
c.u2(0x0030u); // value-length
c.s("ipp://printer.example.com/"); // job 147 on pinetree value
c.s("ipp/print/pinetree/147");
c.u1(0x23u); // enum type value-tag
c.u2(0x0009u); // name-length
c.s("job-state"); // job-state name
c.u2(0x0004u); // value-length
c.u4(0x0003u); // pending value
c.u1(0x03u); // end-of-attributes end-of-
// attributes-tag
ipp::Response_Print_Job r;
r.StatusCode() =
ipp::E_status_code::successful_ok_ignored_or_substituted_attributes;
ipp::Attribute* a = r.unsupported_attributes->AddUnknownAttribute(
"copies", true, ipp::AttrType::integer);
a->SetValue(20);
a = r.unsupported_attributes->AddUnknownAttribute("sides", true,
ipp::AttrType::integer);
a->SetState(ipp::AttrState::unsupported);
r.job_attributes->job_id.Set(147);
r.job_attributes->job_uri.Set(
"ipp://printer.example.com/ipp/print/pinetree/147");
r.job_attributes->job_state.Set(ipp::E_job_state::pending);
CheckResponse(c, &r);
}
TEST(rfc8010, example5) {
// A.5. Print-URI Request
// The following is an example of Print-URI request with "copies" and
// "job-name" parameters:
BinaryContent c;
// Octets Symbolic Value Protocol field
c.u2(0x0101u); // 1.1 version-number
c.u2(0x0003u); // Print-URI operation-id
c.u4(0x00000001u); // 1 request-id
c.u1(0x01u); // start operation- operation-
// attributes attributes-tag
c.u1(0x47u); // charset type value-tag
c.u2(0x0012u); // name-length
c.s("attributes-charset"); // attributes-charset name
c.u2(0x0005u); // value-length
c.s("utf-8"); // UTF-8 value
c.u1(0x48u); // natural-language value-tag
// type
c.u2(0x001bu); // name-length
c.s("attributes-natural-language"); // attributes-natural- name
// language
c.u2(0x0005u); // value-length
c.s("en-us"); // en-US value
c.u1(0x45u); // uri type value-tag
c.u2(0x000bu); // name-length
c.s("printer-uri"); // printer-uri name
c.u2(0x002cu); // value-length
c.s("ipp://printer.example.com/ipp/"); // printer pinetree value
c.s("print/pinetree");
c.u1(0x45u); // uri type value-tag
c.u2(0x000cu); // name-length
c.s("document-uri"); // document-uri name
c.u2(0x0019u); // value-length
c.s("ftp://foo.example.com/foo"); // ftp://foo.example.co value
// m/foo
c.u1(0x42u); // nameWithoutLanguage value-tag
// type
c.u2(0x0008u); // name-length
c.s("job-name"); // job-name name
c.u2(0x0006u); // value-length
c.s("foobar"); // foobar value
c.u1(0x02u); // start job-attributes job-attributes-
// tag
c.u1(0x21u); // integer type value-tag
c.u2(0x0006u); // name-length
c.s("copies"); // copies name
c.u2(0x0004u); // value-length
c.u4(0x00000001u); // 1 value
c.u1(0x03u); // end-of-attributes end-of-
// attributes-tag
ipp::Request_Print_URI r;
r.operation_attributes->printer_uri.Set(
"ipp://printer.example.com/ipp/print/pinetree");
r.operation_attributes->document_uri.Set("ftp://foo.example.com/foo");
r.operation_attributes->job_name.Set("foobar");
r.job_attributes->copies.Set(1);
CheckRequest(c, &r);
}
TEST(rfc8010, example6) {
// A.6. Create-Job Request
// The following is an example of Create-Job request with no parameters
// and no attributes:
BinaryContent c;
// Octets Symbolic Value Protocol field
c.u2(0x0101u); // 1.1 version-number
c.u2(0x0005u); // Create-Job operation-id
c.u4(0x00000001u); // 1 request-id
c.u1(0x01u); // start operation- operation-
// attributes attributes-tag
c.u1(0x47u); // charset type value-tag
c.u2(0x0012u); // name-length
c.s("attributes-charset"); // attributes-charset name
c.u2(0x0005u); // value-length
c.s("utf-8"); // UTF-8 value
c.u1(0x48u); // natural-language value-tag
// type
c.u2(0x001bu); // name-length
c.s("attributes-natural-language"); // attributes-natural- name
// language
c.u2(0x0005u); // value-length
c.s("en-us"); // en-US value
c.u1(0x45u); // uri type value-tag
c.u2(0x000bu); // name-length
c.s("printer-uri"); // printer-uri name
c.u2(0x002cu); // value-length
c.s("ipp://printer.example.com/ipp/"); // printer pinetree value
c.s("print/pinetree");
c.u1(0x03u); // end-of-attributes end-of-
// attributes-tag
ipp::Request_Create_Job r;
r.operation_attributes->printer_uri.Set(
"ipp://printer.example.com/ipp/print/pinetree");
CheckRequest(c, &r);
}
TEST(rfc8010, example7) {
// A.7. Create-Job Request with Collection Attributes
// The following is an example of Create-Job request with the "media-
// col" collection attribute [PWG5100.3] with the value "media-
// size={x-dimension=21000 y-dimension=29700} media-type='stationery'":
BinaryContent c;
// Octets Symbolic Value Protocol field
c.u2(0x0101u); // 1.1 version-number
c.u2(0x0005u); // Create-Job operation-id
c.u4(0x00000001u); // 1 request-id
c.u1(0x01u); // start operation- operation-
// attributes attributes-tag
c.u1(0x47u); // charset type value-tag
c.u2(0x0012u); // name-length
c.s("attributes-charset"); // attributes-charset name
c.u2(0x0005u); // value-length
c.s("utf-8"); // UTF-8 value
c.u1(0x48u); // natural-language value-tag
// type
c.u2(0x001bu); // name-length
c.s("attributes-natural-language"); // attributes-natural- name
// language
c.u2(0x0005u); // value-length
c.s("en-us"); // en-US value
c.u1(0x45u); // uri type value-tag
c.u2(0x000bu); // name-length
c.s("printer-uri"); // printer-uri name
c.u2(0x002cu); // value-length
c.s("ipp://printer.example.com/ipp/"); // printer pinetree value
c.s("print/pinetree");
c.u1(static_cast<int>(ipp::GroupTag::job_attributes)); // missing byte ?
c.u1(0x34u); // begCollection value-tag
c.u2(0x0009u); // 9 name-length
c.s("media-col"); // media-col name
c.u2(0x0000u); // 0 value-length
c.u1(0x4au); // memberAttrName value-tag
c.u2(0x0000u); // 0 name-length
c.u2(0x000au); // 10 value-length
c.s("media-size"); // media-size value (member-
// name)
c.u1(0x34u); // begCollection member-value-tag
c.u2(0x0000u); // 0 name-length
c.u2(0x0000u); // 0 member-value-
// length
c.u1(0x4au); // memberAttrName value-tag
c.u2(0x0000u); // 0 name-length
c.u2(0x000bu); // 11 value-length
c.s("x-dimension"); // x-dimension value (member-
// name)
c.u1(0x21u); // integer member-value-tag
c.u2(0x0000u); // 0 name-length
c.u2(0x0004u); // 4 member-value-
// length
c.u4(0x00005208u); // 21000 member-value
c.u1(0x4au); // memberAttrName value-tag
c.u2(0x0000u); // 0 name-length
c.u2(0x000bu); // 11 value-length
c.s("y-dimension"); // y-dimension value (member-
// name)
c.u1(0x21u); // integer member-value-tag
c.u2(0x0000u); // 0 name-length
c.u2(0x0004u); // 4 member-value-
// length
c.u4(0x00007404u); // 29700 member-value
c.u1(0x37u); // endCollection end-value-tag
c.u2(0x0000u); // 0 end-name-length
c.u2(0x0000u); // 0 end-value-length
c.u1(0x4au); // memberAttrName value-tag
c.u2(0x0000u); // 0 name-length
c.u2(0x000au); // 10 value-length
c.s("media-type"); // media-type value (member-
// name)
c.u1(0x44u); // keyword member-value-tag
c.u2(0x0000u); // 0 name-length
c.u2(0x000au); // 10 member-value-
// length
c.s("stationery"); // stationery member-value
c.u1(0x37u); // endCollection end-value-tag
c.u2(0x0000u); // 0 end-name-length
c.u2(0x0000u); // 0 end-value-length
c.u1(0x03u); // end-of-attributes end-of-
// attributes-tag
ipp::Request_Create_Job r;
r.operation_attributes->printer_uri.Set(
"ipp://printer.example.com/ipp/print/pinetree");
r.job_attributes->media_col->media_size->x_dimension.Set(21000);
r.job_attributes->media_col->media_size->y_dimension.Set(29700);
r.job_attributes->media_col->media_type.Set(ipp::E_media_type::stationery);
CheckRequest(c, &r);
}
TEST(rfc8010, example8) {
// A.8. Get-Jobs Request
// The following is an example of Get-Jobs request with parameters but
// no attributes:
BinaryContent c;
// Octets Symbolic Value Protocol field
c.u2(0x0101u); // 1.1 version-number
c.u2(0x000au); // Get-Jobs operation-id
c.u4(0x0000007bu); // 123 request-id
c.u1(0x01u); // start operation- operation-
// attributes attributes-tag
c.u1(0x47u); // charset type value-tag
c.u2(0x0012u); // name-length
c.s("attributes-charset"); // attributes-charset name
c.u2(0x0005u); // value-length
c.s("utf-8"); // UTF-8 value
c.u1(0x48u); // natural-language value-tag
// type
c.u2(0x001bu); // name-length
c.s("attributes-natural-language"); // attributes-natural- name
// language
c.u2(0x0005u); // value-length
c.s("en-us"); // en-US value
c.u1(0x45u); // uri type value-tag
c.u2(0x000bu); // name-length
c.s("printer-uri"); // printer-uri name
c.u2(0x002cu); // value-length
c.s("ipp://printer.example.com/ipp/"); // printer pinetree value
c.s("print/pinetree");
c.u1(0x21u); // integer type value-tag
c.u2(0x0005u); // name-length
c.s("limit"); // limit name
c.u2(0x0004u); // value-length
c.u4(0x00000032u); // 50 value
c.u1(0x44u); // keyword type value-tag
c.u2(0x0014u); // name-length
c.s("requested-attributes"); // requested-attributes name
c.u2(0x0006u); // value-length
c.s("job-id"); // job-id value
c.u1(0x44u); // keyword type value-tag
c.u2(0x0000u); // additional value name-length
c.u2(0x0008u); // value-length
c.s("job-name"); // job-name value
c.u1(0x44u); // keyword type value-tag
c.u2(0x0000u); // additional value name-length
c.u2(0x000fu); // value-length
c.s("document-format"); // document-format value
c.u1(0x03u); // end-of-attributes end-of-
// attributes-tag
ipp::Request_Get_Jobs r;
r.operation_attributes->printer_uri.Set(
"ipp://printer.example.com/ipp/print/pinetree");
r.operation_attributes->limit.Set(50);
r.operation_attributes->requested_attributes.Set(
{"job-id", "job-name", "document-format"});
CheckRequest(c, &r, 123);
}
TEST(rfc8010, example9) {
// A.9. Get-Jobs Response
// The following is an example of a Get-Jobs response from a previous
// request with three Jobs. The Printer returns no information about
// the second Job (because of security reasons):
BinaryContent c;
// Octets Symbolic Value Protocol field
c.u2(0x0101u); // 1.1 version-number
c.u2(0x0000u); // successful-ok status-code
c.u4(0x0000007bu); // 123 request-id (echoed
// back)
c.u1(0x01u); // start operation- operation-attributes-
// attributes tag
c.u1(0x47u); // charset type value-tag
c.u2(0x0012u); // name-length
c.s("attributes-charset"); // attributes-charset name
c.u2(0x0005u); // value-length
c.s("utf-8"); // UTF-8 value
c.u1(0x48u); // natural-language type value-tag
c.u2(0x001bu); // name-length
c.s("attributes-natural-"); // attributes-natural- name
c.s("language"); // language
c.u2(0x0005u); // value-length
c.s("en-us"); // en-US value
c.u1(0x41u); // textWithoutLanguage value-tag
// type
c.u2(0x000eu); // name-length
c.s("status-message"); // status-message name
c.u2(0x000du); // value-length
c.s("successful-ok"); // successful-ok value
c.u1(0x02u); // start job-attributes job-attributes-tag
// (1st object)
c.u1(0x21u); // integer type value-tag
c.u2(0x0006u); // name-length
c.s("job-id"); // job-id name
c.u2(0x0004u); // value-length
c.u4(147); // 147 value
c.u1(0x36u); // nameWithLanguage value-tag
c.u2(0x0008u); // name-length
c.s("job-name"); // job-name name
c.u2(0x000cu); // value-length
c.u2(0x0005u); // sub-value-length
c.s("fr-ca"); // fr-CA value
c.u2(0x0003u); // sub-value-length
c.s("fou"); // fou name
c.u1(0x02u); // start job-attributes job-attributes-tag
// (2nd object)
c.u1(0x02u); // start job-attributes job-attributes-tag
// (3rd object)
c.u1(0x21u); // integer type value-tag
c.u2(0x0006u); // name-length
c.s("job-id"); // job-id name
c.u2(0x0004u); // value-length
c.u4(149); // 149 value
c.u1(0x36u); // nameWithLanguage value-tag
c.u2(0x0008u); // name-length
c.s("job-name"); // job-name name
c.u2(0x0012u); // value-length
c.u2(0x0005u); // sub-value-length
c.s("de-CH"); // de-CH value
c.u2(0x0009u); // sub-value-length
c.s("isch guet"); // isch guet name
c.u1(0x03u); // end-of-attributes end-of-attributes-tag
ipp::Response_Get_Jobs r;
r.job_attributes[0].job_id.Set(147);
r.job_attributes[0].job_name.Set(ipp::StringWithLanguage("fou", "fr-ca"));
r.job_attributes[2].job_id.Set(149);
r.job_attributes[2].job_name.Set(
ipp::StringWithLanguage("isch guet", "de-CH"));
CheckResponse(c, &r, 123);
}
} // namespace
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}