1 /*-
2  * Public Domain 2014-2018 MongoDB, Inc.
3  * Public Domain 2008-2014 WiredTiger, Inc.
4  *
5  * This is free and unencumbered software released into the public domain.
6  *
7  * Anyone is free to copy, modify, publish, use, compile, sell, or
8  * distribute this software, either in source code form or as a compiled
9  * binary, for any purpose, commercial or non-commercial, and by any
10  * means.
11  *
12  * In jurisdictions that recognize copyright laws, the author or authors
13  * of this software dedicate any and all copyright interest in the
14  * software to the public domain. We make this dedication for the benefit
15  * of the public at large and to the detriment of our heirs and
16  * successors. We intend this dedication to be an overt act of
17  * relinquishment in perpetuity of all present and future rights to this
18  * software under copyright law.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26  * OTHER DEALINGS IN THE SOFTWARE.
27  */
28 package com.wiredtiger.test;
29 
30 import java.util.Arrays;
31 import com.wiredtiger.db.Connection;
32 import com.wiredtiger.db.Cursor;
33 import com.wiredtiger.db.Session;
34 import com.wiredtiger.db.WiredTigerException;
35 import com.wiredtiger.db.WiredTigerPackingException;
36 import com.wiredtiger.db.wiredtiger;
37 
38 import static org.junit.Assert.assertEquals;
39 
40 import org.junit.Test;
41 import org.junit.Assert;
42 import org.junit.runner.RunWith;
43 import org.junit.runners.JUnit4;
44 
45 public class PackTest02 {
46 
47     public static final String TEST_NAME = "PackTest02";
48 
49     private Connection connection;
50     private Session session;
51 
52     // Compare two byte arrays, assert if different
compareByteArrays(byte[] a1, byte[] a2)53     void compareByteArrays(byte[] a1, byte[] a2) {
54         //printByteArray(a1, a1.length);
55         //printByteArray(a2, a2.length);
56         if (a1.length != a2.length) {
57             System.err.println("Length differ");
58         }
59         assertEquals(a1.length, a2.length);
60         for (int i = 0; i < a1.length; i++) {
61             if (a1[i] != a2[i])
62                 System.err.println("DIFFER at " + i);
63             assertEquals(a1[i], a2[i]);
64         }
65     }
66 
67     // Add either a set of keys or a set of values to the
68     // cursor at the current position.
addKeyValues(Cursor cursor, Object[] args, boolean iskey)69     boolean addKeyValues(Cursor cursor, Object[] args, boolean iskey) {
70         for (Object arg : args) {
71             if (arg instanceof Integer) {
72                 if (iskey)
73                     cursor.putKeyInt((Integer)arg);
74                 else
75                     cursor.putValueInt((Integer)arg);
76             }
77             else if (arg instanceof String) {
78                 if (iskey)
79                     cursor.putKeyString((String)arg);
80                 else
81                     cursor.putValueString((String)arg);
82             }
83             else if (arg instanceof byte[]) {
84                 if (iskey)
85                     cursor.putKeyByteArray((byte[])arg);
86                 else
87                     cursor.putValueByteArray((byte[])arg);
88             }
89             else
90                 throw new IllegalArgumentException("unknown type");
91         }
92         return true;
93     }
94 
95     // Check that either a set of keys or a set of values match
96     // the given expected values.  Assert when different.
checkKeyValues(Cursor cursor, Object[] args, boolean iskey)97     boolean checkKeyValues(Cursor cursor, Object[] args, boolean iskey) {
98         for (Object arg : args) {
99             if (arg instanceof Integer) {
100                 if (iskey)
101                     assertEquals(arg, cursor.getKeyInt());
102                 else
103                     assertEquals(arg, cursor.getValueInt());
104             }
105             else if (arg instanceof String) {
106                 if (iskey)
107                     assertEquals(arg, cursor.getKeyString());
108                 else
109                     assertEquals(arg, cursor.getValueString());
110             }
111             else if (arg instanceof byte[]) {
112                 if (iskey)
113                     compareByteArrays((byte[])arg, cursor.getKeyByteArray());
114                 else
115                     compareByteArrays((byte[])arg, cursor.getValueByteArray());
116             }
117             else
118                 throw new IllegalArgumentException("unknown type");
119         }
120         return true;
121     }
122 
123     // Helper function to make an array out of variable args
makeArray(Object... args)124     Object[] makeArray(Object... args)
125     {
126         return args;
127     }
128 
129     // Use checkCompare for the common case that what
130     // we store is what we expect.
check(String fmt, Object... args)131     boolean check(String fmt, Object... args)
132     {
133         return checkCompare(fmt, args, args);
134     }
135 
136     // Create a table with 'fmt' as the value, and also a
137     // reverse index.  Store the given arguments as values,
138     // make sure we can retrieve them from the main table
139     // and the index.  We compare the result using compareArgs,
140     // these may be different from what we store due to padding.
checkCompare(String fmt, Object[] storeArgs, Object[] compareArgs)141     boolean checkCompare(String fmt, Object[] storeArgs, Object[] compareArgs)
142         throws WiredTigerException {
143         String uri = "table:" + TEST_NAME + "-" + fmt;
144         String idx_uri = "index:" + TEST_NAME + "-" + fmt + ":inverse";
145         int nargs = storeArgs.length;
146         String colnames = "";
147         for (int i = 0; i < nargs; i++) {
148             if (i > 0)
149                 colnames += ",";
150             colnames += "v" + i;
151         }
152         session.create(uri, "columns=(k," + colnames + ")," +
153                        "key_format=i,value_format=" + fmt);
154         session.create(idx_uri, "columns=(" + colnames + ")");
155         Cursor forw = session.open_cursor(uri, null, null);
156         Cursor forw_idx = session.open_cursor(idx_uri + "(k)", null, null);
157 
158         forw.putKeyInt(1234);
159         if (!addKeyValues(forw, storeArgs, false))
160             return false;
161         forw.insert();
162 
163         forw.putKeyInt(1234);
164         assertEquals(0, forw.search());
165         if (!checkKeyValues(forw, compareArgs, false))
166             return false;
167 
168         if (!addKeyValues(forw_idx, storeArgs, true))
169             return false;
170         assertEquals(0, forw_idx.search());
171 
172         Integer expected[] = { 1234 };
173 
174         if (!checkKeyValues(forw_idx, expected, false))
175             return false;
176 
177         forw.close();
178         forw_idx.close();
179         session.drop(idx_uri, null);
180         session.drop(uri, null);
181         return true;
182     }
183 
184     // A debug helper method
printByteArray(byte[] bytes, int len)185     private void printByteArray(byte[] bytes, int len) {
186         for (int i = 0; i < len; i++) {
187             System.out.println(String.format(
188                                    "\t%8s", Integer.toBinaryString(
189                                        bytes[i] & 0xff)).replace(' ', '0'));
190         }
191     }
192 
setup()193     private void setup() {
194         connection = wiredtiger.open("WT_HOME", "create");
195         session = connection.open_session(null);
196     }
197 
teardown()198     private void teardown() {
199         session.close(null);
200         connection.close(null);
201     }
202 
203     @Test
packTest()204     public void packTest()
205     throws WiredTigerPackingException {
206 
207         // Do a test of packing, based on test suite's test_pack.py
208 
209         String a10 = "aaaaaaaaaa";
210         String a42 = a10 + a10 + a10 + a10 + "aa";
211         byte[] b10 =
212             { 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42 };
213         byte[] b20 =
214             { 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
215               0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42 };
216         byte[] b1 = { 0x4 };
217         byte[] b3 = { 0x4, 0x0, 0x0 };
218 
219         setup();
220         check("iii", 0, 101, -99);
221         check("3i", 0, 101, -99);
222         check("iS", 42, "forty two");
223         check("S", "abc");
224         check("9S", "aaaaaaaaa");
225         check("9sS", "forty two", "spam egg");
226         check("42s", a42);
227         check("42sS", a42, "something");
228         check("S42s", "something", a42);
229         // nul terminated string with padding
230         check("10sS", "aaaaa\0\0\0\0\0", "something");
231         check("S10s", "something", "aaaaa\0\0\0\0\0");
232         check("u", b20);
233         check("uu", b10, b10);
234         // input 1 byte for a 3 byte format, extra null bytes will be stored
235         checkCompare("3u", makeArray(b1), makeArray(b3));
236         checkCompare("3uu", makeArray(b1, b10), makeArray(b3, b10));
237         checkCompare("u3u", makeArray(b10, b1), makeArray(b10, b3));
238 
239         check("s", "4");
240         check("1s", "4");
241         check("2s", "42");
242         teardown();
243     }
244 
main(String[] args)245     public static void main(String[] args) {
246         PackTest02 tester = new PackTest02();
247         try {
248             tester.packTest();
249         } catch (WiredTigerPackingException wtpe) {
250             System.err.println("Packing exception: " + wtpe);
251         }
252     }
253 }
254